summaryrefslogtreecommitdiff
path: root/DynamicTablesPkg
diff options
context:
space:
mode:
Diffstat (limited to 'DynamicTablesPkg')
-rw-r--r--DynamicTablesPkg/DynamicTables.dsc.inc2
-rw-r--r--DynamicTablesPkg/DynamicTablesPkg.ci.yaml3
-rw-r--r--DynamicTablesPkg/DynamicTablesPkg.dec6
-rw-r--r--DynamicTablesPkg/DynamicTablesPkg.dsc1
-rw-r--r--DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h13
-rw-r--r--DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h117
-rw-r--r--DynamicTablesPkg/Include/Library/Tpm2DeviceTableLib.h50
-rw-r--r--DynamicTablesPkg/Library/Acpi/Common/AcpiTpm2Lib/AcpiTpm2Lib.inf5
-rw-r--r--DynamicTablesPkg/Library/Acpi/Common/AcpiTpm2Lib/Tpm2Generator.c251
-rw-r--r--DynamicTablesPkg/Library/Acpi/X64/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.c533
-rw-r--r--DynamicTablesPkg/Library/Acpi/X64/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf32
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c460
-rw-r--r--DynamicTablesPkg/Library/Common/Tpm2DeviceTableLib/Tpm2DeviceTableLib.c329
-rw-r--r--DynamicTablesPkg/Library/Common/Tpm2DeviceTableLib/Tpm2DeviceTableLib.inf33
-rw-r--r--DynamicTablesPkg/Library/Common/Tpm2DeviceTableLib/Tpm2DeviceTableTemplate.asl44
15 files changed, 1828 insertions, 51 deletions
diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc
index 371efe9..d8c92de 100644
--- a/DynamicTablesPkg/DynamicTables.dsc.inc
+++ b/DynamicTablesPkg/DynamicTables.dsc.inc
@@ -25,6 +25,7 @@
SmbiosStringTableLib|DynamicTablesPkg/Library/Common/SmbiosStringTableLib/SmbiosStringTableLib.inf
MetadataObjLib|DynamicTablesPkg/Library/Common/MetadataObjLib/MetadataObjLib.inf
MetadataHandlerLib|DynamicTablesPkg/Library/Common/MetadataHandlerLib/MetadataHandlerLib.inf
+ Tpm2DeviceTableLib|DynamicTablesPkg/Library/Common/Tpm2DeviceTableLib/Tpm2DeviceTableLib.inf
[LibraryClasses.AARCH64]
DynamicTablesScmiInfoLib|DynamicTablesPkg/Library/DynamicTablesScmiInfoLib/DynamicTablesScmiInfoLib.inf
@@ -67,6 +68,7 @@
DynamicTablesPkg/Library/Acpi/X64/AcpiMadtLib/AcpiMadtLib.inf
DynamicTablesPkg/Library/Acpi/X64/AcpiSsdtHpetLib/AcpiSsdtHpetLib.inf
DynamicTablesPkg/Library/Acpi/X64/AcpiWsmtLib/AcpiWsmtLib.inf
+ DynamicTablesPkg/Library/Acpi/X64/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf
#
# Dynamic Table Factory Dxe
diff --git a/DynamicTablesPkg/DynamicTablesPkg.ci.yaml b/DynamicTablesPkg/DynamicTablesPkg.ci.yaml
index 5c4efb4..56069e2 100644
--- a/DynamicTablesPkg/DynamicTablesPkg.ci.yaml
+++ b/DynamicTablesPkg/DynamicTablesPkg.ci.yaml
@@ -54,7 +54,8 @@
"EmbeddedPkg/EmbeddedPkg.dec",
"DynamicTablesPkg/DynamicTablesPkg.dec",
"MdeModulePkg/MdeModulePkg.dec",
- "MdePkg/MdePkg.dec"
+ "MdePkg/MdePkg.dec",
+ "SecurityPkg/SecurityPkg.dec"
],
# For host based unit tests
"AcceptableDependencies-HOST_APPLICATION":[
diff --git a/DynamicTablesPkg/DynamicTablesPkg.dec b/DynamicTablesPkg/DynamicTablesPkg.dec
index 87934c5..71e76e6 100644
--- a/DynamicTablesPkg/DynamicTablesPkg.dec
+++ b/DynamicTablesPkg/DynamicTablesPkg.dec
@@ -52,6 +52,9 @@
## @libraryclass Defines a set of APIs to a handle Metadata generation/validation.
MetadataHandlerLib|Include/Library/MetadataHandlerLib.h
+ ## @libraryclass Defines a set of methods for generating Tpm2 Device Table method.
+ Tpm2DeviceTableLib|Include/Library/Tpm2DeviceTableLib.h
+
[LibraryClasses.AARCH64]
## @libraryclass Defines a set of APIs to populate CmObj using SCMI.
DynamicTablesScmiInfoLib|Include/Library/DynamicTablesScmiInfoLib.h
@@ -84,5 +87,8 @@
# BIT0: Allow the absence of some registers in the _CPC object.
gEdkiiDynamicTablesPkgTokenSpaceGuid.PcdDevelopmentPlatformRelaxations|0|UINT64|0x4000000A
+ # Generate Tpm2 device table when generate TPM2 acpi table together.
+ gEdkiiDynamicTablesPkgTokenSpaceGuid.PcdGenTpm2DeviceTable|FALSE|BOOLEAN|0x4000000B
+
[Guids]
gEdkiiDynamicTablesPkgTokenSpaceGuid = { 0xab226e66, 0x31d8, 0x4613, { 0x87, 0x9d, 0xd2, 0xfa, 0xb6, 0x10, 0x26, 0x3c } }
diff --git a/DynamicTablesPkg/DynamicTablesPkg.dsc b/DynamicTablesPkg/DynamicTablesPkg.dsc
index 823b3fe..d8c0477 100644
--- a/DynamicTablesPkg/DynamicTablesPkg.dsc
+++ b/DynamicTablesPkg/DynamicTablesPkg.dsc
@@ -51,6 +51,7 @@
DynamicTablesPkg/Library/Common/SmbiosStringTableLib/SmbiosStringTableLib.inf
DynamicTablesPkg/Library/Common/MetadataObjLib/MetadataObjLib.inf
DynamicTablesPkg/Library/Common/MetadataHandlerLib/MetadataHandlerLib.inf
+ DynamicTablesPkg/Library/Common/Tpm2DeviceTableLib/Tpm2DeviceTableLib.inf
[Components.ARM, Components.AARCH64]
DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtHwInfoParserLib.inf
diff --git a/DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h b/DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h
index a642aec..33e976c 100644
--- a/DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h
+++ b/DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h
@@ -71,6 +71,7 @@ typedef enum ArchCommonObjectID {
EArchCommonObjMemoryLatBwInfo, ///< 43 - Memory Latency Bandwidth Info
EArchCommonObjMemoryCacheInfo, ///< 44 - Memory Cache Info
EArchCommonObjSpcrInfo, ///< 45 - Serial Terminal and Interrupt Info
+ EArchCommonObjTpm2DeviceInfo, ///< 46 - TPM2 Device Info
EArchCommonObjMax
} EARCH_COMMON_OBJECT_ID;
@@ -724,6 +725,18 @@ typedef struct CmArchCommonTpm2InterfaceInfo {
UINT64 Lasa;
} CM_ARCH_COMMON_TPM2_INTERFACE_INFO;
+/** A structure that describes TPM2 device.
+
+ ID: EArchCommonObjTpm2DeviceInfo
+*/
+typedef struct CmArchCommonTpm2DeviceInfo {
+ /** TPM2 Device's Base Address */
+ UINT64 Tpm2DeviceBaseAddress;
+
+ /** TPM2 Device' Size */
+ UINT64 Tpm2DeviceSize;
+} CM_ARCH_COMMON_TPM2_DEVICE_INFO;
+
/** A structure that describes the
SPMI (Service Processor Management Interface) Info.
diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
index 9e294ac..a966148 100644
--- a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
+++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
@@ -2107,4 +2107,121 @@ AmlCreatePssNode (
OUT AML_OBJECT_NODE_HANDLE *NewPssNode OPTIONAL
);
+/** Code generation for the IRQ Descriptor.
+
+ The Resource Data effectively created is an IRQ Resource
+ Data. Cf ACPI 6.5 specification:
+ - s6.4.2.1 "IRQ Descriptor"
+ - s19.6.66 "IRQ (Interrupt Resource Descriptor Macro)"
+
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @param [in] IsEdgeTriggered The interrupt is edge triggered or
+ level triggered.
+ @param [in] IsActiveLow The interrupt is active-high or active-low.
+ @param [in] IsShared The interrupt can be shared with other
+ devices or not (Exclusive).
+ @param [in] IrqList List of IRQ numbers. Must be non-NULL.
+ @param [in] IrqCount Number of IRQs in IrqList. Must be > 0 and <= 16.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data node
+ to the list of resource data elements of this node.
+ @param [out] NewRdNode If provided and success, contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval various Other errors as indicated.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdIrq (
+ IN BOOLEAN IsEdgeTriggered,
+ IN BOOLEAN IsActiveLow,
+ IN BOOLEAN IsShared,
+ IN UINT8 *IrqList,
+ IN UINT8 IrqCount,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode OPTIONAL,
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ );
+
+/** Code generation for the UARTSerialBusV2() ASL macro.
+
+ The Resource Data effectively created is a UART Serial Bus Connection
+ Resource Descriptor Resource Data.
+ Cf ACPI 6.5:
+ - s19.6.143 UARTSerialBusV2
+ (UART Serial Bus Connection Resource Descriptor Version 2 Macro)
+ - s6.4.3.8.2.3 UART Serial Bus Connection Resource Descriptor
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @param [in] InitialBaudRate Initial baud rate.
+ @param [in] BitsPerByte Number of bits per byte.
+ Optional, default is 8.
+ @param [in] StopBits Number of stop bits.
+ Optional, default is 1.
+ @param [in] LinesInUse Number of lines in use.
+ @param [in] IsBigEndian Indicates whether the bit transfer is big-endian.
+ Optional, default is FALSE (little-endian).
+ @param [in] Parity Parity format used.
+ Optional, default is no parity.
+ @param [in] FlowControl Flow control protocol used.
+ Optional, default is no flow control.
+ @param [in] ReceiveBufferSize Size of the receive buffer.
+ @param [in] TransmitBufferSize Size of the transmit buffer.
+ @param [in] ResourceSource Name of source resource used.
+ @param [in] ResourceSourceLength Length of the Resource Source.
+ @param [in] ResourceSourceIndex Resource Source index.
+ Optional, default is 0.
+ @param [in] ResourceUsage Resource usage, TRUE for consumer,
+ FALSE for producer.
+ Optional, default is TRUE (consumer).
+ @param [in] IsShared Indicates whether the resource is shared.
+ Optional, default is FALSE (exclusive).
+ @param [in] VendorDefinedData Vendor defined data.
+ Optional, can be NULL.
+ @param [in] VendorDefinedDataLength Length of the vendor defined data.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data
+ node to the list of resource data elements
+ of this node.
+ @param [out] NewRdNode If provided and success,
+ contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval various Various failure values of called functions.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdUartSerialBusV2 (
+ IN UINT32 InitialBaudRate,
+ IN UINT8 *BitsPerByte OPTIONAL,
+ IN UINT8 *StopBits OPTIONAL,
+ IN UINT8 LinesInUse,
+ IN BOOLEAN *IsBigEndian OPTIONAL,
+ IN UINT8 *Parity OPTIONAL,
+ IN UINT8 *FlowControl OPTIONAL,
+ IN UINT16 ReceiveBufferSize,
+ IN UINT16 TransmitBufferSize,
+ IN CHAR8 *ResourceSource,
+ IN UINT16 ResourceSourceLength,
+ IN UINT8 *ResourceSourceIndex OPTIONAL,
+ IN BOOLEAN *ResourceUsage OPTIONAL,
+ IN BOOLEAN *IsShared OPTIONAL,
+ IN UINT8 *VendorDefinedData OPTIONAL,
+ IN UINT16 VendorDefinedDataLength,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode OPTIONAL,
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ );
+
#endif // AML_LIB_H_
diff --git a/DynamicTablesPkg/Include/Library/Tpm2DeviceTableLib.h b/DynamicTablesPkg/Include/Library/Tpm2DeviceTableLib.h
new file mode 100644
index 0000000..5da8117
--- /dev/null
+++ b/DynamicTablesPkg/Include/Library/Tpm2DeviceTableLib.h
@@ -0,0 +1,50 @@
+/** @file
+ Tpm2 device table generating Library
+
+ Copyright (c) 2025, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef TPM2_DEVICE_TABLE_LIB_H_
+#define TPM2_DEVICE_TABLE_LIB_H_
+
+/** Build a SSDT table describing the TPM2 device.
+
+ The table created by this function must be freed by FreeTpm2DeviceTable.
+
+ @param [in] TpmDevInfo TPM2 Device info to describe in the SSDT table.
+ @param [in] Name The Name to give to the Device.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+ @param [in] Uid UID for the TPM@ device.
+ @param [out] Table If success, pointer to the created SSDT table.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+BuildTpm2DeviceTable (
+ IN CONST CM_ARCH_COMMON_TPM2_DEVICE_INFO *TpmDevInfo,
+ IN CONST CHAR8 *Name,
+ IN CONST UINT64 Uid,
+ OUT EFI_ACPI_DESCRIPTION_HEADER **Table
+ );
+
+/** Free an Tpm2 device table previously created by
+ the BuildTpm2DeviceTable function.
+
+ @param [in] Table Pointer to a Tpm2 Device table allocated by
+ the BuildTpm2DeviceTable function.
+
+**/
+VOID
+EFIAPI
+FreeTpm2DeviceTable (
+ IN EFI_ACPI_DESCRIPTION_HEADER *Table
+ );
+
+#endif // TPM2_DEVICE_TABLE_LIB_H_
diff --git a/DynamicTablesPkg/Library/Acpi/Common/AcpiTpm2Lib/AcpiTpm2Lib.inf b/DynamicTablesPkg/Library/Acpi/Common/AcpiTpm2Lib/AcpiTpm2Lib.inf
index ee50fc6..1623e4d 100644
--- a/DynamicTablesPkg/Library/Acpi/Common/AcpiTpm2Lib/AcpiTpm2Lib.inf
+++ b/DynamicTablesPkg/Library/Acpi/Common/AcpiTpm2Lib/AcpiTpm2Lib.inf
@@ -26,4 +26,9 @@
MdePkg/MdePkg.dec
[LibraryClasses]
+ AcpiHelperLib
BaseLib
+ Tpm2DeviceTableLib
+
+[FixedPcd]
+ gEdkiiDynamicTablesPkgTokenSpaceGuid.PcdGenTpm2DeviceTable
diff --git a/DynamicTablesPkg/Library/Acpi/Common/AcpiTpm2Lib/Tpm2Generator.c b/DynamicTablesPkg/Library/Acpi/Common/AcpiTpm2Lib/Tpm2Generator.c
index c743e20..9e39eb5 100644
--- a/DynamicTablesPkg/Library/Acpi/Common/AcpiTpm2Lib/Tpm2Generator.c
+++ b/DynamicTablesPkg/Library/Acpi/Common/AcpiTpm2Lib/Tpm2Generator.c
@@ -20,13 +20,16 @@
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
#include <Protocol/AcpiTable.h>
// Module specific include files.
#include <AcpiTableGenerator.h>
#include <ConfigurationManagerObject.h>
#include <ConfigurationManagerHelper.h>
+#include <Library/AcpiHelperLib.h>
#include <Library/TableHelperLib.h>
+#include <Library/Tpm2DeviceTableLib.h>
#include <Protocol/ConfigurationManagerProtocol.h>
#include <IndustryStandard/Tpm2Acpi.h>
@@ -35,6 +38,9 @@
#define START_METHOD_CRB_WITH_SMC_PARAM_SIZE 12
#define START_METHOD_CRB_WITH_FFA_PARM_SIZE 12
+#define TPM2_DEVICE_UID 0
+#define MAX_TABLE_COUNT 2
+
/**
ARM standard TPM2 Generator
@@ -53,6 +59,12 @@ GET_OBJECT_LIST (
CM_ARCH_COMMON_TPM2_INTERFACE_INFO
);
+GET_OBJECT_LIST (
+ EObjNameSpaceArchCommon,
+ EArchCommonObjTpm2DeviceInfo,
+ CM_ARCH_COMMON_TPM2_DEVICE_INFO
+ );
+
/**
Sanity check Start Method Specific Parameters field
@@ -122,6 +134,73 @@ AcpiTpm2CheckStartMethodParameters (
return EFI_SUCCESS;
}
+/** Build a TPM2 ACPI table.
+
+ @param [in] This Pointer to the table generator.
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] TpmInfo TpmInfo to describe TPM2 device.
+ @param [in, out] Tpm2AcpiTable Tpm2AcpiTable.
+ @param [in] TableSize Size of Tpm2AcpiTable.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildTpm2AcpiTable (
+ IN CONST ACPI_TABLE_GENERATOR *CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
+ IN CONST CM_ARCH_COMMON_TPM2_INTERFACE_INFO *TpmInfo,
+ IN OUT EFI_TPM2_ACPI_TABLE *Tpm2AcpiTable,
+ IN UINT32 TableSize
+ )
+{
+ EFI_STATUS Status;
+ UINT32 *Laml;
+ UINT64 *Lasa;
+
+ Status = AddAcpiHeader (
+ CfgMgrProtocol,
+ This,
+ &Tpm2AcpiTable->Header,
+ AcpiTableInfo,
+ TableSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: TPM2: Failed to add ACPI header. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ Tpm2AcpiTable->Flags = TpmInfo->PlatformClass;
+ Tpm2AcpiTable->AddressOfControlArea = TpmInfo->AddressOfControlArea;
+ Tpm2AcpiTable->StartMethod = TpmInfo->StartMethod;
+
+ CopyMem (
+ Tpm2AcpiTable + 1,
+ TpmInfo->StartMethodParameters,
+ TpmInfo->StartMethodParametersSize
+ );
+
+ if (TpmInfo->Laml > 0) {
+ Lasa = (UINT64 *)((UINT8 *)Tpm2AcpiTable + TableSize - sizeof (TpmInfo->Lasa));
+ Laml = (UINT32 *)((UINT8 *)Lasa - sizeof (TpmInfo->Laml));
+ *Laml = TpmInfo->Laml;
+ *Lasa = TpmInfo->Lasa;
+ }
+
+ return EFI_SUCCESS;
+}
+
/** Construct the TPM2 ACPI table.
Called by the Dynamic Table Manager, this function invokes the
@@ -135,7 +214,8 @@ AcpiTpm2CheckStartMethodParameters (
@param [in] AcpiTableInfo Pointer to the ACPI Table Info.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
- @param [out] Table Pointer to the constructed ACPI Table.
+ @param [out] Table Pointer to a list of generated ACPI table(s).
+ @param [out] TableCount Number of generated ACPI table(s).
@retval EFI_SUCCESS Table generated successfully.
@retval EFI_INVALID_PARAMETER A parameter is invalid.
@@ -148,22 +228,24 @@ AcpiTpm2CheckStartMethodParameters (
STATIC
EFI_STATUS
EFIAPI
-BuildTpm2Table (
+BuildTpm2TableEx (
IN CONST ACPI_TABLE_GENERATOR *CONST This,
IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
- OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table
+ OUT EFI_ACPI_DESCRIPTION_HEADER ***Table,
+ OUT UINTN *CONST TableCount
)
{
EFI_STATUS Status;
- UINT32 TableSize;
CM_ARCH_COMMON_TPM2_INTERFACE_INFO *TpmInfo;
- EFI_TPM2_ACPI_TABLE *Tpm2;
- UINT32 *Laml;
- UINT64 *Lasa;
+ CM_ARCH_COMMON_TPM2_DEVICE_INFO *TpmDevInfo;
+ UINT32 TableSize;
UINT32 MaxParameterSize;
+ EFI_ACPI_DESCRIPTION_HEADER **TableList;
+ CHAR8 NewName[AML_NAME_SEG_SIZE + 1];
- *Table = NULL;
+ *Table = NULL;
+ *TableCount = 0;
ASSERT (
(This != NULL) &&
@@ -233,9 +315,24 @@ BuildTpm2Table (
TableSize += sizeof (TpmInfo->Laml) + sizeof (TpmInfo->Lasa);
}
+ // Allocate a table to store pointers to the TPM2 table and
+ // Ssdt table.for Tpm2 device description.
+ TableList = (EFI_ACPI_DESCRIPTION_HEADER **)
+ AllocateZeroPool (
+ (sizeof (EFI_ACPI_DESCRIPTION_HEADER *) * MAX_TABLE_COUNT)
+ );
+ if (TableList == NULL) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: TPM2: Failed to allocate memory for TableList.\n"
+ ));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
// Allocate the Buffer for TPM2 table
- *Table = (EFI_ACPI_DESCRIPTION_HEADER *)AllocateZeroPool (TableSize);
- if (*Table == NULL) {
+ TableList[0] = (EFI_ACPI_DESCRIPTION_HEADER *)AllocateZeroPool (TableSize);
+ if (TableList[0] == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
DEBUG ((
DEBUG_ERROR,
"ERROR: TPM2: Failed to allocate memory for TPM2 Table, Size = %d," \
@@ -243,51 +340,85 @@ BuildTpm2Table (
TableSize,
Status
));
- return EFI_OUT_OF_RESOURCES;
+ goto ErrorHandler;
}
- Tpm2 = (EFI_TPM2_ACPI_TABLE *)*Table;
-
- Status = AddAcpiHeader (
- CfgMgrProtocol,
+ Status = BuildTpm2AcpiTable (
This,
- &Tpm2->Header,
AcpiTableInfo,
+ CfgMgrProtocol,
+ TpmInfo,
+ (EFI_TPM2_ACPI_TABLE *)TableList[0],
TableSize
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
- "ERROR: TPM2: Failed to add ACPI header. Status = %r\n",
+ "ERROR: TPM2: Failed to Build TPM2 ACPI Table, " \
+ " Status = %r\n",
Status
));
- goto error_handler;
+ goto ErrorHandler;
}
- Tpm2->Flags = TpmInfo->PlatformClass;
- Tpm2->AddressOfControlArea = TpmInfo->AddressOfControlArea;
- Tpm2->StartMethod = TpmInfo->StartMethod;
-
- CopyMem (
- Tpm2 + 1,
- TpmInfo->StartMethodParameters,
- TpmInfo->StartMethodParametersSize
- );
-
- if (TpmInfo->Laml > 0) {
- Laml = (UINT32 *)((UINT8 *)Tpm2 + sizeof (EFI_TPM2_ACPI_TABLE) + MaxParameterSize);
- Lasa = (UINT64 *)((UINT8 *)Laml + sizeof (TpmInfo->Laml));
- *Laml = TpmInfo->Laml;
- *Lasa = TpmInfo->Lasa;
+ *TableCount += 1;
+
+ // Generate TPM2 device SSDT table.
+ if (FixedPcdGetBool (PcdGenTpm2DeviceTable)) {
+ Status = GetEArchCommonObjTpm2DeviceInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &TpmDevInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Failed to get TPM2 Device CM Object %r\n",
+ __func__,
+ Status
+ ));
+ goto ErrorHandler;
+ }
+
+ NewName[0] = 'T';
+ NewName[1] = 'P';
+ NewName[2] = 'M';
+ NewName[3] = AsciiFromHex ((UINT8)(TPM2_DEVICE_UID));
+ NewName[4] = '\0';
+
+ Status = BuildTpm2DeviceTable (
+ TpmDevInfo,
+ NewName,
+ TPM2_DEVICE_UID,
+ &TableList[1]
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: TPM2: Failed to Build SSDT table for TPM2 device," \
+ " Status = %r\n",
+ Status
+ ));
+ goto ErrorHandler;
+ }
+
+ *TableCount += 1;
}
+ *Table = TableList;
+
return EFI_SUCCESS;
-error_handler:
+ErrorHandler:
+ *TableCount = 0;
+
+ if (TableList != NULL) {
+ if (TableList[0] != NULL) {
+ FreePool (TableList[0]);
+ }
- if (*Table != NULL) {
- FreePool (*Table);
- *Table = NULL;
+ FreePool (TableList);
}
return Status;
@@ -299,7 +430,10 @@ error_handler:
@param [in] AcpiTableInfo Pointer to the ACPI Table Info.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
- @param [in, out] Table Pointer to the ACPI Table.
+ @param [in, out] Table Pointer to an array of pointers
+ to ACPI Table(s).
+ @param [in] TableCount Number of ACPI table(s).
+
@retval EFI_SUCCESS The resources were freed successfully.
@retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
@@ -307,13 +441,17 @@ error_handler:
STATIC
EFI_STATUS
EFIAPI
-FreeTpm2TableResources (
- IN CONST ACPI_TABLE_GENERATOR *CONST This,
- IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
- IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
- IN OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table
+FreeTpm2TableResourcesEx (
+ IN CONST ACPI_TABLE_GENERATOR *CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER ***CONST Table,
+ IN CONST UINTN TableCount
)
{
+ UINTN Idx;
+ EFI_ACPI_DESCRIPTION_HEADER **TableList;
+
ASSERT (
(This != NULL) &&
(AcpiTableInfo != NULL) &&
@@ -322,12 +460,27 @@ FreeTpm2TableResources (
(AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature)
);
- if ((Table == NULL) || (*Table == NULL)) {
+ if ((Table == NULL) || (*Table == NULL) || (TableCount == 0)) {
DEBUG ((DEBUG_ERROR, "ERROR: TPM2: Invalid Table Pointer\n"));
return EFI_INVALID_PARAMETER;
}
- FreePool (*Table);
+ TableList = *Table;
+
+ for (Idx = 0; Idx < TableCount; Idx++) {
+ switch (TableList[Idx]->Signature) {
+ case EFI_ACPI_6_5_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE:
+ FreePool (TableList[Idx]);
+ break;
+ case EFI_ACPI_6_5_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
+ FreeTpm2DeviceTable (TableList[Idx]);
+ break;
+ default:
+ ASSERT (0);
+ }
+ }
+
+ FreePool (TableList);
*Table = NULL;
return EFI_SUCCESS;
@@ -357,14 +510,14 @@ ACPI_TABLE_GENERATOR Tpm2Generator = {
// Creator Revision
TPM2_GENERATOR_REVISION,
// Build Table function
- BuildTpm2Table,
+ NULL,
// Free Resource function
- FreeTpm2TableResources,
- // Extended build function not needed
NULL,
+ // Extended build function not needed
+ BuildTpm2TableEx,
// Extended build function not implemented by the generator.
// Hence extended free resource function is not required.
- NULL
+ FreeTpm2TableResourcesEx
};
/** Register the Generator with the ACPI Table Factory.
diff --git a/DynamicTablesPkg/Library/Acpi/X64/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.c b/DynamicTablesPkg/Library/Acpi/X64/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.c
new file mode 100644
index 0000000..b6e7c46
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/X64/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.c
@@ -0,0 +1,533 @@
+/** @file
+ SSDT Serial Port Fixup Library for X64.
+
+
+ Copyright (c) 2019 - 2024, Arm Limited. All rights reserved.<BR>
+ Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - Arm Server Base Boot Requirements (SBBR), s4.2.1.8 "SPCR".
+ - Microsoft Debug Port Table 2 (DBG2) Specification - December 10, 2015.
+ - ACPI for Arm Components 1.0 - 2020
+ - Arm Generic Interrupt Controller Architecture Specification,
+ Issue H, January 2022.
+ (https://developer.arm.com/documentation/ihi0069/)
+**/
+
+#include <IndustryStandard/DebugPort2Table.h>
+#include <Library/AcpiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/AcpiTable.h>
+
+// Module specific include files.
+#include <AcpiTableGenerator.h>
+#include <ConfigurationManagerObject.h>
+#include <ConfigurationManagerHelper.h>
+#include <Library/AcpiHelperLib.h>
+#include <Library/AmlLib/AmlLib.h>
+#include <Protocol/ConfigurationManagerProtocol.h>
+
+/** UART address range length.
+*/
+#define MIN_UART_ADDRESS_LENGTH 0x1000U
+
+/** Validate the Serial Port Information.
+
+ @param [in] SerialPortInfoTable Table of CM_ARCH_COMMON_SERIAL_PORT_INFO.
+ @param [in] SerialPortCount Count of SerialPort in the table.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+ValidateSerialPortInfo (
+ IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfoTable,
+ IN UINT32 SerialPortCount
+ )
+{
+ UINT32 Index;
+ CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo;
+
+ if ((SerialPortInfoTable == NULL) ||
+ (SerialPortCount == 0))
+ {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Index = 0; Index < SerialPortCount; Index++) {
+ SerialPortInfo = &SerialPortInfoTable[Index];
+ ASSERT (SerialPortInfo != NULL);
+
+ if ((SerialPortInfo == NULL) ||
+ (SerialPortInfo->BaseAddress == 0))
+ {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: UART port base address is invalid. BaseAddress = 0x%llx\n",
+ SerialPortInfo->BaseAddress
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((SerialPortInfo->PortSubtype !=
+ EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_PL011_UART) &&
+ (SerialPortInfo->PortSubtype !=
+ EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART_2X) &&
+ (SerialPortInfo->PortSubtype !=
+ EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART) &&
+ (SerialPortInfo->PortSubtype !=
+ EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_DCC) &&
+ (SerialPortInfo->PortSubtype !=
+ EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550) &&
+ (SerialPortInfo->PortSubtype !=
+ EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_16550_WITH_GAS))
+ {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: UART port subtype is invalid."
+ " UART Base = 0x%llx, PortSubtype = 0x%x\n",
+ SerialPortInfo->BaseAddress,
+ SerialPortInfo->PortSubtype
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((DEBUG_INFO, "UART Configuration:\n"));
+ DEBUG ((
+ DEBUG_INFO,
+ " UART Base = 0x%llx\n",
+ SerialPortInfo->BaseAddress
+ ));
+ DEBUG ((
+ DEBUG_INFO,
+ " Length = 0x%llx\n",
+ SerialPortInfo->BaseAddressLength
+ ));
+ DEBUG ((DEBUG_INFO, " Clock = %lu\n", SerialPortInfo->Clock));
+ DEBUG ((DEBUG_INFO, " BaudRate = %llu\n", SerialPortInfo->BaudRate));
+ DEBUG ((DEBUG_INFO, " Interrupt = %lu\n", SerialPortInfo->Interrupt));
+ } // for
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create the _CRS (Current Resource Settings) AML node for a serial port device.
+
+ @param [in] SerialPortInfo Pointer to the serial port information structure.
+ @param [in] Name The Name to give to the Device.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+ @param [in] DeviceNode AML device node handle.
+
+ @retval EFI_SUCCESS The CRS node was created successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval Others Failed to create CRS node.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CreateSerialPortCrs (
+ IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo,
+ IN CONST CHAR8 *Name,
+ IN AML_OBJECT_NODE_HANDLE DeviceNode
+ )
+{
+ AML_OBJECT_NODE_HANDLE CrsNode;
+ EFI_STATUS Status;
+ UINT8 IrqList[1];
+
+ Status = AmlCodeGenNameResourceTemplate ("_CRS", DeviceNode, &CrsNode);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to create AML _CRS Node."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ IrqList[0] = SerialPortInfo->Interrupt & MAX_UINT8;
+
+ if (SerialPortInfo->PortSubtype == EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550) {
+ Status = AmlCodeGenRdIo (
+ TRUE,
+ SerialPortInfo->BaseAddress & MAX_UINT16,
+ SerialPortInfo->BaseAddress & MAX_UINT16,
+ 1,
+ 0x8,
+ CrsNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to generate IO RD node."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ //
+ // Generate the IRQ() ASL macro.
+ // This is used for legacy X86/X64/PC-AT compatible systems.
+ //
+ Status = AmlCodeGenRdIrq (
+ TRUE,
+ TRUE,
+ TRUE,
+ IrqList,
+ ARRAY_SIZE (IrqList),
+ CrsNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to generate IRQ RD node."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ //
+ // Generate the UARTSerialBusV2() ASL macro.
+ // This describes legacy COM port resources for X86/X64/PC-AT compatible systems.
+ //
+ Status = AmlCodeGenRdUartSerialBusV2 (
+ SerialPortInfo->BaudRate & MAX_UINT32, // BaudRate
+ NULL, // Default 8 Bits Per Byte
+ NULL, // Default 1 Stop Bit
+ 0, // Lines in Use
+ NULL, // Default is little endian
+ NULL, // Default is no parity
+ NULL, // Default is no flow control
+ 0x1, // ReceiveBufferSize
+ 0x1, // TransmitBufferSize
+ (CHAR8 *)Name, // Serial Port Name
+ (AsciiStrLen (Name) + 1) & MAX_UINT16, // Serial Port Name Length
+ NULL, // Default resource index is zero
+ NULL, // Default is consumer
+ NULL, // Default is exclusive
+ NULL, // vendor defined data
+ 0, // VendorDefinedDataLength
+ CrsNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to generate UartSerialBus RD node."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ if (SerialPortInfo->PortSubtype == EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_16550_WITH_GAS) {
+ Status = AmlCodeGenRdMemory32Fixed (
+ TRUE,
+ SerialPortInfo->BaseAddress & MAX_UINT32,
+ ((SerialPortInfo->BaseAddressLength > MIN_UART_ADDRESS_LENGTH)
+ ? SerialPortInfo->BaseAddressLength
+ : MIN_UART_ADDRESS_LENGTH) & MAX_UINT32,
+ CrsNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to generate MMIO RD node."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ Status = AmlCodeGenRdIrq (
+ TRUE,
+ TRUE,
+ TRUE,
+ IrqList,
+ 1,
+ CrsNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to generate IRQ RD node."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** Build a SSDT table describing the input serial port.
+
+ The table created by this function must be freed by FreeSsdtSerialTable.
+
+ @param [in] AcpiTableInfo Pointer to the ACPI table information.
+ @param [in] SerialPortInfo Serial port to describe in the SSDT table.
+ @param [in] Name The Name to give to the Device.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+ @param [in] Uid UID for the Serial Port.
+ @param [out] Table If success, pointer to the created SSDT table.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+BuildSsdtSerialPortTable (
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *AcpiTableInfo,
+ IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo,
+ IN CONST CHAR8 *Name,
+ IN CONST UINT64 Uid,
+ OUT EFI_ACPI_DESCRIPTION_HEADER **Table
+ )
+{
+ AML_OBJECT_NODE_HANDLE DeviceNode;
+ AML_OBJECT_NODE_HANDLE ScopeNode;
+ AML_ROOT_NODE_HANDLE RootNode;
+ CONST CHAR8 *NonBsaHid;
+ EFI_STATUS Status;
+ EFI_STATUS Status1;
+ UINT32 EisaId;
+
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (SerialPortInfo != NULL);
+ ASSERT (Name != NULL);
+ ASSERT (Table != NULL);
+
+ // Validate the Serial Port Info.
+ Status = ValidateSerialPortInfo (SerialPortInfo, 1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = AmlCodeGenDefinitionBlock (
+ "SSDT",
+ "AMDINC",
+ "SERIAL",
+ 0x01,
+ &RootNode
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to create AML Definition Block."
+ " Status = %r\n",
+ Status
+ ));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ Status = AmlCodeGenScope ("\\_SB_", RootNode, &ScopeNode);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to create AML Scope Node."
+ " Status = %r\n",
+ Status
+ ));
+ goto exit_handler;
+ }
+
+ // Create the Device Node, COMx, where x is the Uid.
+ Status = AmlCodeGenDevice (Name, ScopeNode, &DeviceNode);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to create AML Device Node."
+ " Status = %r\n",
+ Status
+ ));
+ goto exit_handler;
+ }
+
+ NonBsaHid = (CONST CHAR8 *)PcdGetPtr (PcdNonBsaCompliant16550SerialHid);
+ if (SerialPortInfo->PortSubtype == EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_16550_WITH_GAS) {
+ if ((NonBsaHid != NULL) && (AsciiStrLen (NonBsaHid) != 0)) {
+ if (!(IsValidPnpId (NonBsaHid) || IsValidAcpiId (NonBsaHid))) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Invalid Supplied HID %a.\n",
+ NonBsaHid
+ ));
+ goto exit_handler;
+ }
+
+ Status = AmlCodeGenNameString (
+ "_HID",
+ NonBsaHid,
+ DeviceNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to create AML _HID Node."
+ " Status = %r\n",
+ Status
+ ));
+ goto exit_handler;
+ }
+ }
+ }
+
+ if ((SerialPortInfo->PortSubtype == EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550) ||
+ ((SerialPortInfo->PortSubtype == EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_16550_WITH_GAS) &&
+ ((NonBsaHid == NULL) || (AsciiStrLen (NonBsaHid) == 0))))
+ {
+ Status = AmlGetEisaIdFromString ("PNP0501", &EisaId);
+ if (EFI_ERROR (Status)) {
+ goto exit_handler;
+ }
+
+ Status = AmlCodeGenNameInteger ("_HID", EisaId, DeviceNode, NULL);
+ if (EFI_ERROR (Status)) {
+ goto exit_handler;
+ }
+
+ Status = AmlGetEisaIdFromString ("PNP0500", &EisaId);
+ if (EFI_ERROR (Status)) {
+ goto exit_handler;
+ }
+
+ Status = AmlCodeGenNameInteger ("_CID", EisaId, DeviceNode, NULL);
+ if (EFI_ERROR (Status)) {
+ goto exit_handler;
+ }
+ }
+
+ // _UID
+ Status = AmlCodeGenNameInteger ("_UID", Uid, DeviceNode, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to create AML _UID Node."
+ " Status = %r\n",
+ Status
+ ));
+ goto exit_handler;
+ }
+
+ // _DDN
+ Status = AmlCodeGenNameString ("_DDN", Name, DeviceNode, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to create AML _DDN Node."
+ " Status = %r\n",
+ Status
+ ));
+ goto exit_handler;
+ }
+
+ // _STA
+ Status = AmlCodeGenMethodRetInteger (
+ "_STA",
+ 0x0F,
+ 0,
+ FALSE,
+ 0,
+ DeviceNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to create AML _STA Node."
+ " Status = %r\n",
+ Status
+ ));
+ goto exit_handler;
+ }
+
+ Status = CreateSerialPortCrs (SerialPortInfo, Name, DeviceNode);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to create _CRS for Serial Port."
+ " Status = %r\n",
+ Status
+ ));
+ goto exit_handler;
+ }
+
+ // Serialize the tree.
+ Status = AmlSerializeDefinitionBlock (
+ RootNode,
+ Table
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to Serialize SSDT Table Data."
+ " Status = %r\n",
+ Status
+ ));
+ }
+
+ return EFI_SUCCESS;
+
+exit_handler:
+ // Cleanup
+ if (RootNode != NULL) {
+ Status1 = AmlDeleteTree (RootNode);
+ if (EFI_ERROR (Status1)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to cleanup AML tree."
+ " Status = %r\n",
+ Status1
+ ));
+ // If Status was success but we failed to delete the AML Tree
+ // return Status1 else return the original error code, i.e. Status.
+ if (!EFI_ERROR (Status)) {
+ return Status1;
+ }
+ }
+ }
+
+ return Status;
+}
+
+/** Free an SSDT table previously created by
+ the BuildSsdtSerialTable function.
+
+ @param [in] Table Pointer to a SSDT table allocated by
+ the BuildSsdtSerialTable function.
+
+ @retval EFI_SUCCESS Success.
+**/
+EFI_STATUS
+EFIAPI
+FreeSsdtSerialPortTable (
+ IN EFI_ACPI_DESCRIPTION_HEADER *Table
+ )
+{
+ ASSERT (Table != NULL);
+ FreePool (Table);
+ return EFI_SUCCESS;
+}
diff --git a/DynamicTablesPkg/Library/Acpi/X64/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf b/DynamicTablesPkg/Library/Acpi/X64/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf
new file mode 100644
index 0000000..73ae99b
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/X64/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf
@@ -0,0 +1,32 @@
+## @file
+# SSDT Serial Port fixup Library
+#
+# Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 1.30
+ BASE_NAME = DynamicSsdtSerialPortFixupLib
+ FILE_GUID = 83F367CE-9EA3-4A5B-B61F-60E06CA7D9FF
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = SsdtSerialPortFixupLib
+
+[Sources]
+ SsdtSerialPortFixupLib.c
+
+[Packages.common]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ DynamicTablesPkg/DynamicTablesPkg.dec
+
+[LibraryClasses]
+ AcpiHelperLib
+ AmlLib
+ BaseLib
+
+[Pcd]
+ gEdkiiDynamicTablesPkgTokenSpaceGuid.PcdNonBsaCompliant16550SerialHid
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
index bf0d7b0..8be5eab 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
@@ -2,7 +2,7 @@
AML Resource Data Code Generation.
Copyright (c) 2020 - 2021, Arm Limited. All rights reserved.<BR>
- Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ Copyright (C) 2023 - 2025 Advanced Micro Devices, Inc. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -1670,3 +1670,461 @@ error_handler:
return Status;
}
+
+/** Code generation for the IRQ Descriptor.
+
+ The Resource Data effectively created is an IRQ Resource
+ Data. Cf ACPI 6.5 specification:
+ - s6.4.2.1 "IRQ Descriptor"
+ - s19.6.66 "IRQ (Interrupt Resource Descriptor Macro)"
+
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @param [in] IsEdgeTriggered The interrupt is edge triggered or
+ level triggered.
+ @param [in] IsActiveLow The interrupt is active-high or active-low.
+ @param [in] IsShared The interrupt can be shared with other
+ devices or not (Exclusive).
+ @param [in] IrqList List of IRQ numbers. Must be non-NULL.
+ @param [in] IrqCount Number of IRQs in IrqList. Must be > 0 and <= 16.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data node
+ to the list of resource data elements of this node.
+ @param [out] NewRdNode If provided and success, contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval various Other errors as indicated.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdIrq (
+ IN BOOLEAN IsEdgeTriggered,
+ IN BOOLEAN IsActiveLow,
+ IN BOOLEAN IsShared,
+ IN UINT8 *IrqList,
+ IN UINT8 IrqCount,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode OPTIONAL,
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ )
+{
+ AML_DATA_NODE *RdNode;
+ EFI_ACPI_IRQ_DESCRIPTOR IrqDesc;
+ EFI_STATUS Status;
+ UINT8 Index;
+ UINT16 Mask;
+
+ if ((NameOpNode == NULL) && (NewRdNode == NULL)) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((IsEdgeTriggered && !IsActiveLow) ||
+ (!IsEdgeTriggered && IsActiveLow))
+ {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((IrqList == NULL) || (IrqCount == 0) || (IrqCount > 16)) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Mask = 0;
+ for (Index = 0; Index < IrqCount; Index++) {
+ if (IrqList[Index] > 16) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Mask & (1 << IrqList[Index])) != 0) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Mask |= (1 << IrqList[Index]);
+ }
+
+ if (Mask == 0) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IrqDesc.Header.Bits.Type = ACPI_SMALL_ITEM_FLAG;
+ IrqDesc.Header.Bits.Name = ACPI_SMALL_IRQ_DESCRIPTOR_NAME;
+ IrqDesc.Header.Bits.Length = sizeof (EFI_ACPI_IRQ_DESCRIPTOR) -
+ sizeof (ACPI_SMALL_RESOURCE_HEADER);
+ IrqDesc.Mask = Mask;
+ IrqDesc.Information = (IsEdgeTriggered ? BIT0 : 0) |
+ (IsActiveLow ? BIT3 : 0) |
+ (IsShared ? BIT4 : 0);
+
+ Status = AmlCreateDataNode (
+ EAmlNodeDataTypeResourceData,
+ (UINT8 *)&IrqDesc,
+ sizeof (EFI_ACPI_IRQ_DESCRIPTOR),
+ &RdNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ return LinkRdNode (RdNode, NameOpNode, NewRdNode);
+}
+
+/** Code generation for the UART Serial Bus Connection Resource Descriptor.
+
+ The Resource Data effectively created is a UART Serial Bus Connection
+ Resource Descriptor Resource Data.
+ Cf ACPI 6.5:
+ - s19.6.143 UARTSerialBusV2
+ (UART Serial Bus Connection Resource Descriptor Version 2 Macro)
+ - s6.4.3.8.2.3 UART Serial Bus Connection Resource Descriptor
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @param [in] IsResourceConsumer ResourceUsage parameter.
+ @param [in] IsSlaveMode Indicates whether the uart operates in slave mode.
+ @param [in] IsBigEndian Indicates whether the bit transfer is big-endian.
+ @param [in] BitsPerByte Indicates the number of bits per byte.
+ @param [in] StopBits Specifies the stop bits format used.
+ @param [in] FlowControl Specifies the flow control protocol used.
+ @param [in] BaudRate Specifies the baud rate.
+ @param [in] RxFifo Number of bytes in the receiver FIFO.
+ @param [in] TxFifo Number of bytes in the transmitter FIFO.
+ @param [in] Parity Specifies the parity format used.
+ @param [in] SerialLinesEnabled Specifies which serial lines are enabled.
+ @param [in] VendorDefinedData VendorDefinedData parameter.
+ @param [in] VendorDefinedDataLength VendorDefinedDataLength parameter.
+ @param [in] ResourceSource Name of source resource used.
+ @param [in] ResourceSourceLength Resource Source Length.
+ @param [in] NameOpNode NameOpNode object node defining a named object.
+ If provided, append the new resource data
+ node to the list of resource data elements
+ of this node.
+ @param [out] NewRdNode If provided and success,
+ contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+ @retval various Other errors as indicated.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdUartSerialBus (
+ IN BOOLEAN IsResourceConsumer,
+ IN BOOLEAN IsSlaveMode,
+ IN BOOLEAN IsBigEndian,
+ IN UINT8 BitsPerByte,
+ IN UINT8 StopBits,
+ IN UINT8 FlowControl,
+ IN UINT32 BaudRate,
+ IN UINT16 RxFifo,
+ IN UINT16 TxFifo,
+ IN UINT8 Parity,
+ IN UINT8 SerialLinesEnabled,
+ IN UINT8 *VendorDefinedData OPTIONAL,
+ IN UINT16 VendorDefinedDataLength,
+ IN CHAR8 *ResourceSource,
+ IN UINT16 ResourceSourceLength,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode OPTIONAL,
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ )
+{
+ AML_DATA_NODE *RdNode;
+ EFI_STATUS Status;
+ UINT16 UartDescBuffLength;
+ UINT8 *UartDescBuff;
+ UINT8 BitsPerByteMask;
+
+ EFI_ACPI_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR UartDesc;
+
+ if ((NameOpNode == NULL) && (NewRdNode == NULL)) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((VendorDefinedData == NULL) && (VendorDefinedDataLength > 0)) ||
+ ((VendorDefinedData != NULL) && (VendorDefinedDataLength == 0)))
+ {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((ResourceSource == NULL) || (ResourceSourceLength <= 0)) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (StopBits > EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_STOP_BIT_2) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (FlowControl > EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_FC_XON_XOFF) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Parity > EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_PARITY_SPACE) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (BitsPerByte) {
+ case 5:
+ BitsPerByteMask = EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_5_BITS_PER_BYTE;
+ break;
+ case 6:
+ BitsPerByteMask = EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_6_BITS_PER_BYTE;
+ break;
+ case 7:
+ BitsPerByteMask = EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_7_BITS_PER_BYTE;
+ break;
+ case 8:
+ BitsPerByteMask = EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_8_BITS_PER_BYTE;
+ break;
+ case 9:
+ BitsPerByteMask = EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_9_BITS_PER_BYTE;
+ break;
+ default:
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /// as per spec last two bits are reserved and must be 0.
+ if ((SerialLinesEnabled &
+ ~(EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_LIN_RTS |
+ EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_LIN_CTS |
+ EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_LIN_DTR |
+ EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_LIN_DSR |
+ EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_LIN_RI |
+ EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_LIN_DTD)) != 0)
+ {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UartDesc.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
+ UartDesc.Header.Header.Bits.Name = ACPI_LARGE_GENERIC_SERIAL_BUS_CONNECTION_DESCRIPTOR_NAME;
+ UartDesc.RevisionId = EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_REVISION_ID;
+ UartDesc.ResourceSourceIndex = 0;
+ UartDesc.SerialBusType = EFI_ACPI_SERIAL_BUS_RESOURCE_TYPE_UART;
+ UartDesc.GeneralFlags = (IsResourceConsumer ? BIT1 : 0) |
+ (IsSlaveMode ? BIT0 : 0);
+ UartDesc.TypeSpecificFlags = (IsBigEndian ? BIT7 : 0) |
+ (BitsPerByteMask << 4) |
+ (StopBits << 2) |
+ (FlowControl);
+ UartDesc.TypeSpecificRevisionId = EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_REVISION_ID;
+ /// TypeDataLength is the length of the data following the TypeDataLength,
+ /// up to the Additional vendor supplied data (not included).
+ UartDesc.TypeDataLength = sizeof (UartDesc.DefaultBaudRate) +
+ sizeof (UartDesc.RxFIFO) +
+ sizeof (UartDesc.TxFIFO) +
+ sizeof (UartDesc.Parity) +
+ sizeof (UartDesc.SerialLinesEnabled) +
+ VendorDefinedDataLength;
+ UartDesc.DefaultBaudRate = BaudRate;
+ UartDesc.RxFIFO = RxFifo;
+ UartDesc.TxFIFO = TxFifo;
+ UartDesc.Parity = Parity;
+ UartDesc.SerialLinesEnabled = SerialLinesEnabled;
+
+ UartDescBuffLength = sizeof (EFI_ACPI_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR) +
+ VendorDefinedDataLength +
+ ResourceSourceLength;
+
+ UartDesc.Header.Length = UartDescBuffLength - sizeof (ACPI_LARGE_RESOURCE_HEADER);
+
+ UartDescBuff = AllocateZeroPool (UartDescBuffLength);
+ if (UartDescBuff == NULL) {
+ ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (
+ UartDescBuff,
+ &UartDesc,
+ sizeof (EFI_ACPI_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR)
+ );
+
+ if (VendorDefinedData != NULL) {
+ CopyMem (
+ UartDescBuff + sizeof (EFI_ACPI_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR),
+ VendorDefinedData,
+ VendorDefinedDataLength
+ );
+ }
+
+ CopyMem (
+ UartDescBuff +
+ sizeof (EFI_ACPI_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR) +
+ VendorDefinedDataLength,
+ ResourceSource,
+ ResourceSourceLength
+ );
+
+ Status = AmlCreateDataNode (
+ EAmlNodeDataTypeResourceData,
+ UartDescBuff,
+ UartDescBuffLength,
+ &RdNode
+ );
+ FreePool (UartDescBuff);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ return LinkRdNode (RdNode, NameOpNode, NewRdNode);
+}
+
+/** Code generation for the UARTSerialBusV2() ASL macro.
+
+ The Resource Data effectively created is a UART Serial Bus Connection
+ Resource Descriptor Resource Data.
+ Cf ACPI 6.5:
+ - s19.6.143 UARTSerialBusV2
+ (UART Serial Bus Connection Resource Descriptor Version 2 Macro)
+ - s6.4.3.8.2.3 UART Serial Bus Connection Resource Descriptor
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @param [in] InitialBaudRate Initial baud rate.
+ @param [in] BitsPerByte Number of bits per byte.
+ Optional, default is 8.
+ @param [in] StopBits Number of stop bits.
+ Optional, default is 1.
+ @param [in] LinesInUse Number of lines in use.
+ @param [in] IsBigEndian Indicates whether the bit transfer is big-endian.
+ Optional, default is FALSE (little-endian).
+ @param [in] Parity Parity format used.
+ Optional, default is no parity.
+ @param [in] FlowControl Flow control protocol used.
+ Optional, default is no flow control.
+ @param [in] ReceiveBufferSize Size of the receive buffer.
+ @param [in] TransmitBufferSize Size of the transmit buffer.
+ @param [in] ResourceSource Name of source resource used.
+ @param [in] ResourceSourceLength Length of the Resource Source.
+ @param [in] ResourceSourceIndex Resource Source index.
+ Optional, default is 0.
+ @param [in] ResourceUsage Resource usage, TRUE for consumer,
+ FALSE for producer.
+ Optional, default is TRUE (consumer).
+ @param [in] IsShared Indicates whether the resource is shared.
+ Optional, default is FALSE (exclusive).
+ @param [in] VendorDefinedData Vendor defined data.
+ Optional, can be NULL.
+ @param [in] VendorDefinedDataLength Length of the vendor defined data.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data
+ node to the list of resource data elements
+ of this node.
+ @param [out] NewRdNode If provided and success,
+ contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval various Various failure values of called functions.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdUartSerialBusV2 (
+ IN UINT32 InitialBaudRate,
+ IN UINT8 *BitsPerByte OPTIONAL,
+ IN UINT8 *StopBits OPTIONAL,
+ IN UINT8 LinesInUse,
+ IN BOOLEAN *IsBigEndian OPTIONAL,
+ IN UINT8 *Parity OPTIONAL,
+ IN UINT8 *FlowControl OPTIONAL,
+ IN UINT16 ReceiveBufferSize,
+ IN UINT16 TransmitBufferSize,
+ IN CHAR8 *ResourceSource,
+ IN UINT16 ResourceSourceLength,
+ IN UINT8 *ResourceSourceIndex OPTIONAL,
+ IN BOOLEAN *ResourceUsage OPTIONAL,
+ IN BOOLEAN *IsShared OPTIONAL,
+ IN UINT8 *VendorDefinedData OPTIONAL,
+ IN UINT16 VendorDefinedDataLength,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode OPTIONAL,
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ if ((NameOpNode == NULL) && (NewRdNode == NULL)) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((VendorDefinedData == NULL) && (VendorDefinedDataLength > 0)) ||
+ ((VendorDefinedData != NULL) && (VendorDefinedDataLength == 0)))
+ {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((ResourceSource == NULL) || (ResourceSourceLength <= 0)) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ResourceSourceIndex != NULL) {
+ if (*ResourceSourceIndex != 0) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ Status = AmlCodeGenRdUartSerialBus (
+ /// default is resource consumer
+ (ResourceUsage != NULL) ? *ResourceUsage : TRUE,
+ /// slave mode
+ TRUE,
+ /// default is little-endian
+ (IsBigEndian != NULL) ? *IsBigEndian : FALSE,
+ /// default is 8 bits per byte
+ (BitsPerByte != NULL) ? *BitsPerByte : 8,
+ /// default is 1 stop bit
+ (StopBits != NULL) ? *StopBits : EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_STOP_BIT_1,
+ /// default is no flow control
+ (FlowControl != NULL) ? *FlowControl : EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_TSF_FC_NONE,
+ InitialBaudRate,
+ ReceiveBufferSize,
+ TransmitBufferSize,
+ /// default is no parity
+ (Parity != NULL) ? *Parity : EFI_ACPI_5_0_SERIAL_BUS_RESOURCE_UART_DESCRIPTOR_PARITY_NONE,
+ LinesInUse,
+ VendorDefinedData,
+ VendorDefinedDataLength,
+ ResourceSource,
+ ResourceSourceLength,
+ NameOpNode,
+ NewRdNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/Common/Tpm2DeviceTableLib/Tpm2DeviceTableLib.c b/DynamicTablesPkg/Library/Common/Tpm2DeviceTableLib/Tpm2DeviceTableLib.c
new file mode 100644
index 0000000..22bd001
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/Tpm2DeviceTableLib/Tpm2DeviceTableLib.c
@@ -0,0 +1,329 @@
+/** @file
+ Tpm2 device table generating Library
+
+ Copyright (c) 2025, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - TCG ACPI specification.
+ (https://trustedcomputinggroup.org/resource/tcg-acpi-specification/)
+**/
+#include <IndustryStandard/DebugPort2Table.h>
+#include <Library/AcpiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+
+#include <Protocol/AcpiTable.h>
+
+// Module specific include files.
+#include <AcpiTableGenerator.h>
+#include <ConfigurationManagerObject.h>
+#include <ConfigurationManagerHelper.h>
+#include <Library/AcpiHelperLib.h>
+#include <Library/AmlLib/AmlLib.h>
+#include <Protocol/ConfigurationManagerProtocol.h>
+
+/** C array containing the compiled AML template.
+ This symbol is defined in the auto generated C file
+ containing the AML bytecode array.
+*/
+extern CHAR8 tpm2devicetabletemplate_aml_code[];
+
+/** Fixup the TPM2 device UID (_UID).
+
+ @param [in] RootNodeHandle Pointer to the root of an AML tree.
+ @param [in] Uid UID for the TPM2 device.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FixupTpm2DeviceUid (
+ IN AML_ROOT_NODE_HANDLE RootNodeHandle,
+ IN CONST UINT64 Uid
+ )
+{
+ EFI_STATUS Status;
+ AML_OBJECT_NODE_HANDLE NameOpIdNode;
+
+ // Get the _UID NameOp object defined by the "Name ()" statement,
+ // and update its value.
+ Status = AmlFindNode (
+ RootNodeHandle,
+ "\\_SB_.TPM0._UID",
+ &NameOpIdNode
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return AmlNameOpUpdateInteger (NameOpIdNode, (UINT64)Uid);
+}
+
+/** Fixup the Tpm2 device name.
+
+ @param [in] RootNodeHandle Pointer to the root of an AML tree.
+ @param [in] Name The Name to give to the Device.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FixupTpm2DeviceName (
+ IN AML_ROOT_NODE_HANDLE RootNodeHandle,
+ IN CONST CHAR8 *Name
+ )
+{
+ EFI_STATUS Status;
+ AML_OBJECT_NODE_HANDLE DeviceNode;
+
+ // Get the COM0 variable defined by the "Device ()" statement.
+ Status = AmlFindNode (RootNodeHandle, "\\_SB_.TPM0", &DeviceNode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Update the Device's name.
+ return AmlDeviceOpUpdateName (DeviceNode, Name);
+}
+
+/** Fixup the Tpm2 device _CRS values (BaseAddress, ...).
+
+ @param [in] RootNodeHandle Pointer to the root of an AML tree.
+ @param [in] TpmDevInfo Pointer to a TPM2 device Information
+ structure.
+ Get the device size Information from there.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FixupTpm2DeviceCrs (
+ IN AML_ROOT_NODE_HANDLE RootNodeHandle,
+ IN CONST CM_ARCH_COMMON_TPM2_DEVICE_INFO *TpmDevInfo
+ )
+{
+ EFI_STATUS Status;
+ AML_OBJECT_NODE_HANDLE NameOpCrsNode;
+ AML_DATA_NODE_HANDLE QWordRdNode;
+
+ // Get the "_CRS" object defined by the "Name ()" statement.
+ Status = AmlFindNode (
+ RootNodeHandle,
+ "\\_SB_.TPM0._CRS",
+ &NameOpCrsNode
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Get the first Rd node in the "_CRS" object.
+ Status = AmlNameOpGetFirstRdNode (NameOpCrsNode, &QWordRdNode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (QWordRdNode == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Update the TPM2 device's base address and length.
+ Status = AmlUpdateRdQWord (
+ QWordRdNode,
+ TpmDevInfo->Tpm2DeviceBaseAddress,
+ TpmDevInfo->Tpm2DeviceSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
+/** Fixup the Tpm2 Device in the AML tree.
+
+ For each template value:
+ - find the node to update;
+ - update the value.
+
+ @param [in] RootNodeHandle Pointer to the root of the AML tree.
+ @param [in] TpmDevInfo Pointer to a TPM2 device Information
+ structure.
+ @param [in] Name The Name to give to the Device.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+ @param [in] Uid UID for the TPM2 device.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FixupTpm2DeviceInfo (
+ IN AML_ROOT_NODE_HANDLE RootNodeHandle,
+ IN CONST CM_ARCH_COMMON_TPM2_DEVICE_INFO *TpmDevInfo,
+ IN CONST CHAR8 *Name,
+ IN CONST UINT64 Uid
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (RootNodeHandle != NULL);
+ ASSERT (TpmDevInfo != NULL);
+ ASSERT (Name != NULL);
+
+ // Fixup the _UID value.
+ Status = FixupTpm2DeviceUid (RootNodeHandle, Uid);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Fixup the _CRS values.
+ Status = FixupTpm2DeviceCrs (RootNodeHandle, TpmDevInfo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Fixup the Tpm2 device name.
+ // This MUST be done at the end, otherwise AML paths won't be valid anymore.
+ return FixupTpm2DeviceName (RootNodeHandle, Name);
+}
+
+/** Build a SSDT table describing the TPM2 device.
+
+ The table created by this function must be freed by FreeSImpleTpm2DeviceTable.
+
+ @param [in] TpmDevInfo TPM2 device info to describe in the SSDT table.
+ @param [in] Name The Name to give to the Device.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+ @param [in] Uid UID for the TPM2 device
+ @param [out] Table If success, pointer to the created SSDT table.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+BuildTpm2DeviceTable (
+ IN CONST CM_ARCH_COMMON_TPM2_DEVICE_INFO *TpmDevInfo,
+ IN CONST CHAR8 *Name,
+ IN CONST UINT64 Uid,
+ OUT EFI_ACPI_DESCRIPTION_HEADER **Table
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status1;
+ AML_ROOT_NODE_HANDLE RootNodeHandle;
+
+ ASSERT (TpmDevInfo != NULL);
+ ASSERT (Name != NULL);
+ ASSERT (Table != NULL);
+
+ // Parse the Tpm2 Device Table Template.
+ Status = AmlParseDefinitionBlock (
+ (EFI_ACPI_DESCRIPTION_HEADER *)tpm2devicetabletemplate_aml_code,
+ &RootNodeHandle
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: TPM2-DEVICE-FIXUP:"
+ " Failed to parse SSDT TPM2 device Template. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Fixup the template values.
+ Status = FixupTpm2DeviceInfo (
+ RootNodeHandle,
+ TpmDevInfo,
+ Name,
+ Uid
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: TPM2-DEVICE-FIXUP: Failed to fixup SSDT TPM2 Device Table."
+ " Status = %r\n",
+ Status
+ ));
+ goto ExitHandler;
+ }
+
+ // Serialize the tree.
+ Status = AmlSerializeDefinitionBlock (
+ RootNodeHandle,
+ Table
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: TPM2-DEVICE-FIXUP: Failed to Serialize SSDT Table Data."
+ " Status = %r\n",
+ Status
+ ));
+ }
+
+ExitHandler:
+ // Cleanup
+ if (RootNodeHandle != NULL) {
+ Status1 = AmlDeleteTree (RootNodeHandle);
+ if (EFI_ERROR (Status1)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: TPM2-DEVICE-FIXUP: Failed to cleanup AML tree."
+ " Status = %r\n",
+ Status1
+ ));
+ // If Status was success but we failed to delete the AML Tree
+ // return Status1 else return the original error code, i.e. Status.
+ if (!EFI_ERROR (Status)) {
+ return Status1;
+ }
+ }
+ }
+
+ return Status;
+}
+
+/** Free an Tpm2 device table previously created by
+ the BuildTpm2DeviceTable function.
+
+ @param [in] Table Pointer to a Tpm2 Device table allocated by
+ the BuildTpm2DeviceTable function.
+
+**/
+VOID
+EFIAPI
+FreeTpm2DeviceTable (
+ IN EFI_ACPI_DESCRIPTION_HEADER *Table
+ )
+{
+ ASSERT (Table != NULL);
+ FreePool (Table);
+}
diff --git a/DynamicTablesPkg/Library/Common/Tpm2DeviceTableLib/Tpm2DeviceTableLib.inf b/DynamicTablesPkg/Library/Common/Tpm2DeviceTableLib/Tpm2DeviceTableLib.inf
new file mode 100644
index 0000000..6c69a9c
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/Tpm2DeviceTableLib/Tpm2DeviceTableLib.inf
@@ -0,0 +1,33 @@
+## @file
+# Tpm2 Device table generating library
+#
+# Copyright (c) 2025, Arm Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = DynamicTpm2DeviceTableLib
+ FILE_GUID = b09d0390-0400-11f0-a447-cfc17b482322
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = Tpm2DeviceTableLib
+
+[Sources]
+ Tpm2DeviceTableLib.c
+ Tpm2DeviceTableTemplate.asl
+
+[Packages.common]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ DynamicTablesPkg/DynamicTablesPkg.dec
+
+[Packages.ARM, Packages.AARCH64]
+ ArmPkg/ArmPkg.dec
+
+[LibraryClasses]
+ AcpiHelperLib
+ AmlLib
+ BaseLib
diff --git a/DynamicTablesPkg/Library/Common/Tpm2DeviceTableLib/Tpm2DeviceTableTemplate.asl b/DynamicTablesPkg/Library/Common/Tpm2DeviceTableLib/Tpm2DeviceTableTemplate.asl
new file mode 100644
index 0000000..9b99767
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/Tpm2DeviceTableLib/Tpm2DeviceTableTemplate.asl
@@ -0,0 +1,44 @@
+/** @file
+ TPM2 Device Table Template
+
+ Copyright (c) 2025, ARM Ltd. All rights reserved.<BR>
+ All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s)
+ - TCG ACPI Specification
+ - TCG PC Client Platform Firmware Profile Specification
+
+ @par Glossary:
+ - {template} - Data fixed up using AML Fixup APIs.
+**/
+
+DefinitionBlock("Tpm2DeviceTableTemplate.aml", "SSDT", 2, "ARMLTD", "TPM2CRB", 1) {
+ Scope(_SB) {
+ Device (TPM0) { // {template}
+ Name (_HID, "MSFT0101")
+ Name (_UID, 0) // {template}
+ Name (_CRS, ResourceTemplate () {
+ QWordMemory (
+ ResourceProducer,
+ PosDecode,
+ MinFixed,
+ MaxFixed,
+ NonCacheable,
+ ReadWrite,
+ 0x0000000000000000, // Granularity
+ 0x00000000FFDFB000, // Range Minimum // {template}
+ 0x00000000FFDFFFFF, // Range Maximum // {template}
+ 0x0000000000000000, // Translation Offset
+ 0x0000000000005000, // Length // {template}
+ ,
+ ,
+ ,
+ AddressRangeReserved,
+ TypeStatic
+ ) // QWordMemory
+ }) // Name
+ } // Device
+ } // Scope(_SB)
+}