summaryrefslogtreecommitdiffstats
path: root/DynamicTablesPkg/Library/Acpi/Arm
diff options
context:
space:
mode:
Diffstat (limited to 'DynamicTablesPkg/Library/Acpi/Arm')
-rw-r--r--DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/AcpiIortLibArm.inf42
-rw-r--r--DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c2081
-rw-r--r--DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.h50
3 files changed, 2173 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/AcpiIortLibArm.inf b/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/AcpiIortLibArm.inf
new file mode 100644
index 0000000000..ce828eb091
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/AcpiIortLibArm.inf
@@ -0,0 +1,42 @@
+## @file
+# IORT Table Generator
+#
+# Copyright (c) 2017 - 2018, ARM Limited. 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.
+##
+
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = AcpiIortLibArm
+ FILE_GUID = 25682BA8-B41D-4403-B034-253769E0DAD5
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = NULL|DXE_DRIVER
+ CONSTRUCTOR = AcpiIortLibConstructor
+ DESTRUCTOR = AcpiIortLibDestructor
+
+[Sources]
+ IortGenerator.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ DynamicTablesPkg/DynamicTablesPkg.dec
+
+[LibraryClasses]
+ BaseLib
+
+[Pcd]
+
+[Protocols]
+
+[Guids]
+
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c b/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c
new file mode 100644
index 0000000000..a3ee60664e
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c
@@ -0,0 +1,2081 @@
+/** @file
+ IORT Table Generator
+
+ Copyright (c) 2017 - 2019, ARM Limited. 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.
+
+ @par Reference(s):
+ - IO Remapping Table, Platform Design Document,
+ Document number: ARM DEN 0049D, Issue D, March 2018
+
+**/
+
+#include <IndustryStandard/IoRemappingTable.h>
+#include <Library/AcpiLib.h>
+#include <Library/BaseLib.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/TableHelperLib.h>
+#include <Protocol/ConfigurationManagerProtocol.h>
+
+#include "IortGenerator.h"
+
+/** ARM standard IORT Generator
+
+Requirements:
+ The following Configuration Manager Object(s) are required by
+ this Generator:
+ - EArmObjItsGroup
+ - EArmObjNamedComponent
+ - EArmObjRootComplex
+ - EArmObjSmmuV1SmmuV2
+ - EArmObjSmmuV3
+ - EArmObjPmcg
+ - EArmObjGicItsIdentifierArray
+ - EArmObjIdMapping
+ - EArmObjGicItsIdentifierArray
+*/
+
+/** This macro expands to a function that retrieves the ITS
+ Group node information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjItsGroup,
+ CM_ARM_ITS_GROUP_NODE
+ );
+
+/** This macro expands to a function that retrieves the
+ Named Component node information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjNamedComponent,
+ CM_ARM_NAMED_COMPONENT_NODE
+ );
+
+/** This macro expands to a function that retrieves the
+ Root Complex node information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjRootComplex,
+ CM_ARM_ROOT_COMPLEX_NODE
+ );
+
+/** This macro expands to a function that retrieves the
+ SMMU v1/v2 node information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjSmmuV1SmmuV2,
+ CM_ARM_SMMUV1_SMMUV2_NODE
+ );
+
+/** This macro expands to a function that retrieves the
+ SMMU v3 node information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjSmmuV3,
+ CM_ARM_SMMUV3_NODE
+ );
+
+/** This macro expands to a function that retrieves the
+ PMCG node information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPmcg,
+ CM_ARM_PMCG_NODE
+ );
+
+/** This macro expands to a function that retrieves the
+ ITS Identifier Array information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjGicItsIdentifierArray,
+ CM_ARM_ITS_IDENTIFIER
+ );
+
+/** This macro expands to a function that retrieves the
+ Id Mapping Array information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjIdMapping,
+ CM_ARM_ID_MAPPING
+ );
+
+/** This macro expands to a function that retrieves the
+ SMMU Interrupt Array information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjSmmuInterruptArray,
+ CM_ARM_SMMU_INTERRUPT
+ );
+
+/** Returns the size of the ITS Group node.
+
+ @param [in] Node Pointer to ITS Group node.
+
+ @retval Size of the ITS Group Node.
+**/
+STATIC
+UINT32
+GetItsGroupNodeSize (
+ IN CONST CM_ARM_ITS_GROUP_NODE * Node
+ )
+{
+ ASSERT (Node != NULL);
+
+ /* Size of ITS Group Node +
+ Size of ITS Identifier array
+ */
+ return sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE) +
+ (Node->ItsIdCount * sizeof (UINT32));
+}
+
+/** Returns the total size required for the ITS Group nodes and
+ updates the Node Indexer.
+
+ This function calculates the size required for the node group
+ and also populates the Node Indexer array with offsets for the
+ individual nodes.
+
+ @param [in] NodeStartOffset Offset from the start of the
+ IORT where this node group starts.
+ @param [in] NodeList Pointer to ITS Group node list.
+ @param [in] NodeCount Count of the ITS Group nodes.
+ @param [in, out] NodeIndexer Pointer to the next Node Indexer.
+
+ @retval Total size of the ITS Group Nodes.
+**/
+STATIC
+UINT32
+GetSizeofItsGroupNodes (
+ IN CONST UINT32 NodeStartOffset,
+ IN CONST CM_ARM_ITS_GROUP_NODE * NodeList,
+ IN UINT32 NodeCount,
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
+ )
+{
+ UINT32 Size;
+
+ ASSERT (NodeList != NULL);
+
+ Size = 0;
+ while (NodeCount-- != 0) {
+ (*NodeIndexer)->Token = NodeList->Token;
+ (*NodeIndexer)->Object = (VOID*)NodeList;
+ (*NodeIndexer)->Offset = Size + NodeStartOffset;
+ DEBUG ((
+ DEBUG_INFO,
+ "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
+ *NodeIndexer,
+ (*NodeIndexer)->Token,
+ (*NodeIndexer)->Object,
+ (*NodeIndexer)->Offset
+ ));
+
+ Size += GetItsGroupNodeSize (NodeList);
+ (*NodeIndexer)++;
+ NodeList++;
+ }
+ return Size;
+}
+
+/** Returns the size of the Named Component node.
+
+ @param [in] Node Pointer to Named Component node.
+
+ @retval Size of the Named Component node.
+**/
+STATIC
+UINT32
+GetNamedComponentNodeSize (
+ IN CONST CM_ARM_NAMED_COMPONENT_NODE * Node
+ )
+{
+ ASSERT (Node != NULL);
+
+ /* Size of Named Component node +
+ Size of ID mapping array +
+ Size of ASCII string + 'padding to 32-bit word aligned'.
+ */
+ return sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE) +
+ (Node->IdMappingCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) +
+ ALIGN_VALUE (AsciiStrSize (Node->ObjectName), 4);
+}
+
+/** Returns the total size required for the Named Component nodes and
+ updates the Node Indexer.
+
+ This function calculates the size required for the node group
+ and also populates the Node Indexer array with offsets for the
+ individual nodes.
+
+ @param [in] NodeStartOffset Offset from the start of the
+ IORT where this node group starts.
+ @param [in] NodeList Pointer to Named Component node list.
+ @param [in] NodeCount Count of the Named Component nodes.
+ @param [in, out] NodeIndexer Pointer to the next Node Indexer.
+
+ @retval Total size of the Named Component nodes.
+**/
+STATIC
+UINT32
+GetSizeofNamedComponentNodes (
+ IN CONST UINT32 NodeStartOffset,
+ IN CONST CM_ARM_NAMED_COMPONENT_NODE * NodeList,
+ IN UINT32 NodeCount,
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
+ )
+{
+ UINT32 Size;
+
+ ASSERT (NodeList != NULL);
+
+ Size = 0;
+ while (NodeCount-- != 0) {
+ (*NodeIndexer)->Token = NodeList->Token;
+ (*NodeIndexer)->Object = (VOID*)NodeList;
+ (*NodeIndexer)->Offset = Size + NodeStartOffset;
+ DEBUG ((
+ DEBUG_INFO,
+ "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
+ *NodeIndexer,
+ (*NodeIndexer)->Token,
+ (*NodeIndexer)->Object,
+ (*NodeIndexer)->Offset
+ ));
+
+ Size += GetNamedComponentNodeSize (NodeList);
+ (*NodeIndexer)++;
+ NodeList++;
+ }
+
+ return Size;
+}
+
+/** Returns the size of the Root Complex node.
+
+ @param [in] Node Pointer to Root Complex node.
+
+ @retval Size of the Root Complex node.
+**/
+STATIC
+UINT32
+GetRootComplexNodeSize (
+ IN CONST CM_ARM_ROOT_COMPLEX_NODE * Node
+ )
+{
+ ASSERT (Node != NULL);
+
+ /* Size of Root Complex node +
+ Size of ID mapping array
+ */
+ return sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE) +
+ (Node->IdMappingCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE));
+}
+
+/** Returns the total size required for the Root Complex nodes and
+ updates the Node Indexer.
+
+ This function calculates the size required for the node group
+ and also populates the Node Indexer array with offsets for the
+ individual nodes.
+
+ @param [in] NodeStartOffset Offset from the start of the
+ IORT where this node group starts.
+ @param [in] NodeList Pointer to Root Complex node list.
+ @param [in] NodeCount Count of the Root Complex nodes.
+ @param [in, out] NodeIndexer Pointer to the next Node Indexer.
+
+ @retval Total size of the Root Complex nodes.
+**/
+STATIC
+UINT32
+GetSizeofRootComplexNodes (
+ IN CONST UINT32 NodeStartOffset,
+ IN CONST CM_ARM_ROOT_COMPLEX_NODE * NodeList,
+ IN UINT32 NodeCount,
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
+ )
+{
+ UINT32 Size;
+
+ ASSERT (NodeList != NULL);
+
+ Size = 0;
+ while (NodeCount-- != 0) {
+ (*NodeIndexer)->Token = NodeList->Token;
+ (*NodeIndexer)->Object = (VOID*)NodeList;
+ (*NodeIndexer)->Offset = Size + NodeStartOffset;
+ DEBUG ((
+ DEBUG_INFO,
+ "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
+ *NodeIndexer,
+ (*NodeIndexer)->Token,
+ (*NodeIndexer)->Object,
+ (*NodeIndexer)->Offset
+ ));
+
+ Size += GetRootComplexNodeSize (NodeList);
+ (*NodeIndexer)++;
+ NodeList++;
+ }
+
+ return Size;
+}
+
+/** Returns the size of the SMMUv1/SMMUv2 node.
+
+ @param [in] Node Pointer to SMMUv1/SMMUv2 node list.
+
+ @retval Size of the SMMUv1/SMMUv2 node.
+**/
+STATIC
+UINT32
+GetSmmuV1V2NodeSize (
+ IN CONST CM_ARM_SMMUV1_SMMUV2_NODE * Node
+ )
+{
+ ASSERT (Node != NULL);
+
+ /* Size of SMMU v1/SMMU v2 node +
+ Size of ID mapping array +
+ Size of context interrupt array +
+ Size of PMU interrupt array
+ */
+ return sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE) +
+ (Node->IdMappingCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) +
+ (Node->ContextInterruptCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)) +
+ (Node->PmuInterruptCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));
+}
+
+/** Returns the total size required for the SMMUv1/SMMUv2 nodes and
+ updates the Node Indexer.
+
+ This function calculates the size required for the node group
+ and also populates the Node Indexer array with offsets for the
+ individual nodes.
+
+ @param [in] NodeStartOffset Offset from the start of the
+ IORT where this node group starts.
+ @param [in] NodeList Pointer to SMMUv1/SMMUv2 node list.
+ @param [in] NodeCount Count of the SMMUv1/SMMUv2 nodes.
+ @param [in, out] NodeIndexer Pointer to the next Node Indexer.
+
+ @retval Total size of the SMMUv1/SMMUv2 nodes.
+**/
+STATIC
+UINT32
+GetSizeofSmmuV1V2Nodes (
+ IN CONST UINT32 NodeStartOffset,
+ IN CONST CM_ARM_SMMUV1_SMMUV2_NODE * NodeList,
+ IN UINT32 NodeCount,
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
+ )
+{
+ UINT32 Size;
+
+ ASSERT (NodeList != NULL);
+
+ Size = 0;
+ while (NodeCount-- != 0) {
+ (*NodeIndexer)->Token = NodeList->Token;
+ (*NodeIndexer)->Object = (VOID*)NodeList;
+ (*NodeIndexer)->Offset = Size + NodeStartOffset;
+ DEBUG ((
+ DEBUG_INFO,
+ "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
+ *NodeIndexer,
+ (*NodeIndexer)->Token,
+ (*NodeIndexer)->Object,
+ (*NodeIndexer)->Offset
+ ));
+
+ Size += GetSmmuV1V2NodeSize (NodeList);
+ (*NodeIndexer)++;
+ NodeList++;
+ }
+ return Size;
+}
+
+/** Returns the size of the SMMUv3 node.
+
+ @param [in] Node Pointer to SMMUv3 node list.
+
+ @retval Total size of the SMMUv3 nodes.
+**/
+STATIC
+UINT32
+GetSmmuV3NodeSize (
+ IN CONST CM_ARM_SMMUV3_NODE * Node
+ )
+{
+ ASSERT (Node != NULL);
+
+ /* Size of SMMU v1/SMMU v2 node +
+ Size of ID mapping array
+ */
+ return sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE) +
+ (Node->IdMappingCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE));
+}
+
+/** Returns the total size required for the SMMUv3 nodes and
+ updates the Node Indexer.
+
+ This function calculates the size required for the node group
+ and also populates the Node Indexer array with offsets for the
+ individual nodes.
+
+ @param [in] NodeStartOffset Offset from the start of the
+ IORT where this node group starts.
+ @param [in] NodeList Pointer to SMMUv3 node list.
+ @param [in] NodeCount Count of the SMMUv3 nodes.
+ @param [in, out] NodeIndexer Pointer to the next Node Indexer.
+
+ @retval Total size of the SMMUv3 nodes.
+**/
+STATIC
+UINT32
+GetSizeofSmmuV3Nodes (
+ IN CONST UINT32 NodeStartOffset,
+ IN CONST CM_ARM_SMMUV3_NODE * NodeList,
+ IN UINT32 NodeCount,
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
+ )
+{
+ UINT32 Size;
+
+ ASSERT (NodeList != NULL);
+
+ Size = 0;
+ while (NodeCount-- != 0) {
+ (*NodeIndexer)->Token = NodeList->Token;
+ (*NodeIndexer)->Object = (VOID*)NodeList;
+ (*NodeIndexer)->Offset = Size + NodeStartOffset;
+ DEBUG ((
+ DEBUG_INFO,
+ "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
+ *NodeIndexer,
+ (*NodeIndexer)->Token,
+ (*NodeIndexer)->Object,
+ (*NodeIndexer)->Offset
+ ));
+
+ Size += GetSmmuV3NodeSize (NodeList);
+ (*NodeIndexer)++;
+ NodeList++;
+ }
+ return Size;
+}
+
+/** Returns the size of the PMCG node.
+
+ @param [in] Node Pointer to PMCG node.
+
+ @retval Size of the PMCG node.
+**/
+STATIC
+UINT32
+GetPmcgNodeSize (
+ IN CONST CM_ARM_PMCG_NODE * Node
+ )
+{
+ ASSERT (Node != NULL);
+
+ /* Size of PMCG node +
+ Size of ID mapping array
+ */
+ return sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE) +
+ (Node->IdMappingCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE));
+}
+
+/** Returns the total size required for the PMCG nodes and
+ updates the Node Indexer.
+
+ This function calculates the size required for the node group
+ and also populates the Node Indexer array with offsets for the
+ individual nodes.
+
+ @param [in] NodeStartOffset Offset from the start of the
+ IORT where this node group starts.
+ @param [in] NodeList Pointer to PMCG node list.
+ @param [in] NodeCount Count of the PMCG nodes.
+ @param [in, out] NodeIndexer Pointer to the next Node Indexer.
+
+ @retval Total size of the PMCG nodes.
+**/
+STATIC
+UINT32
+GetSizeofPmcgNodes (
+ IN CONST UINT32 NodeStartOffset,
+ IN CONST CM_ARM_PMCG_NODE * NodeList,
+ IN UINT32 NodeCount,
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
+ )
+{
+ UINT32 Size;
+
+ ASSERT (NodeList != NULL);
+
+ Size = 0;
+ while (NodeCount-- != 0) {
+ (*NodeIndexer)->Token = NodeList->Token;
+ (*NodeIndexer)->Object = (VOID*)NodeList;
+ (*NodeIndexer)->Offset = Size + NodeStartOffset;
+ DEBUG ((
+ DEBUG_INFO,
+ "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
+ *NodeIndexer,
+ (*NodeIndexer)->Token,
+ (*NodeIndexer)->Object,
+ (*NodeIndexer)->Offset
+ ));
+
+ Size += GetPmcgNodeSize (NodeList);
+ (*NodeIndexer)++;
+ NodeList++;
+ }
+ return Size;
+}
+
+/** Returns the offset of the Node referenced by the Token.
+
+ @param [in] NodeIndexer Pointer to node indexer array.
+ @param [in] NodeCount Count of the nodes.
+ @param [in] Token Reference token for the node.
+ @param [out] NodeOffset Offset of the node from the
+ start of the IORT table.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_NOT_FOUND No matching token reference
+ found in node indexer array.
+**/
+STATIC
+EFI_STATUS
+GetNodeOffsetReferencedByToken (
+ IN IORT_NODE_INDEXER * NodeIndexer,
+ IN UINT32 NodeCount,
+ IN CM_OBJECT_TOKEN Token,
+ OUT UINT32 * NodeOffset
+ )
+{
+ DEBUG ((
+ DEBUG_INFO,
+ "IORT: Node Indexer: Search Token = %p\n",
+ Token
+ ));
+ while (NodeCount-- != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "IORT: Node Indexer: NodeIndexer->Token = %p, Offset = %d\n",
+ NodeIndexer->Token,
+ NodeIndexer->Offset
+ ));
+ if (NodeIndexer->Token == Token) {
+ *NodeOffset = NodeIndexer->Offset;
+ DEBUG ((
+ DEBUG_INFO,
+ "IORT: Node Indexer: Token = %p, Found\n",
+ Token
+ ));
+ return EFI_SUCCESS;
+ }
+ NodeIndexer++;
+ }
+ DEBUG ((
+ DEBUG_INFO,
+ "IORT: Node Indexer: Token = %p, Not Found\n",
+ Token
+ ));
+ return EFI_NOT_FOUND;
+}
+
+/** Update the Id Mapping Array.
+
+ This function retrieves the Id Mapping Array object referenced by the
+ IdMappingToken and updates the IdMapArray.
+
+ @param [in] This Pointer to the table Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] IdMapArray Pointer to an array of Id Mappings.
+ @param [in] IdCount Number of Id Mappings.
+ @param [in] IdMappingToken Reference Token for retrieving the
+ Id Mapping Array object.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+**/
+STATIC
+EFI_STATUS
+AddIdMappingArray (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray,
+ IN UINT32 IdCount,
+ IN CONST CM_OBJECT_TOKEN IdMappingToken
+ )
+{
+ EFI_STATUS Status;
+ CM_ARM_ID_MAPPING * IdMappings;
+ UINT32 IdMappingCount;
+ ACPI_IORT_GENERATOR * Generator;
+
+ ASSERT (IdMapArray != NULL);
+
+ Generator = (ACPI_IORT_GENERATOR*)This;
+
+ // Get the Id Mapping Array
+ Status = GetEArmObjIdMapping (
+ CfgMgrProtocol,
+ IdMappingToken,
+ &IdMappings,
+ &IdMappingCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to get Id Mapping array. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ if (IdMappingCount < IdCount) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to get the required number of Id Mappings.\n"
+ ));
+ return EFI_NOT_FOUND;
+ }
+
+ // Populate the Id Mapping array
+ while (IdCount-- != 0) {
+ Status = GetNodeOffsetReferencedByToken (
+ Generator->NodeIndexer,
+ Generator->IortNodeCount,
+ IdMappings->OutputReferenceToken,
+ &IdMapArray->OutputReference
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to get Output Reference for ITS Identifier array."
+ "Reference Token = %p"
+ " Status = %r\n",
+ IdMappings->OutputReferenceToken,
+ Status
+ ));
+ return Status;
+ }
+
+ IdMapArray->InputBase = IdMappings->InputBase;
+ IdMapArray->NumIds = IdMappings->NumIds;
+ IdMapArray->OutputBase = IdMappings->OutputBase;
+ IdMapArray->Flags = IdMappings->Flags;
+
+ IdMapArray++;
+ IdMappings++;
+ } // Id Mapping array
+
+ return EFI_SUCCESS;
+}
+
+/** Update the ITS Group Node Information.
+
+ @param [in] This Pointer to the table Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Iort Pointer to IORT table structure.
+ @param [in] NodesStartOffset Offset for the start of the ITS Group
+ Nodes.
+ @param [in] NodeList Pointer to an array of ITS Group Node
+ Objects.
+ @param [in] NodeCount Number of ITS Group Node Objects.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+**/
+STATIC
+EFI_STATUS
+AddItsGroupNodes (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort,
+ IN CONST UINT32 NodesStartOffset,
+ IN CONST CM_ARM_ITS_GROUP_NODE * NodeList,
+ IN UINT32 NodeCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE * ItsGroupNode;
+ UINT32 * ItsIds;
+ CM_ARM_ITS_IDENTIFIER * ItsIdentifier;
+ UINT32 ItsIdentifierCount;
+ UINT32 IdIndex;
+
+ ASSERT (Iort != NULL);
+
+ ItsGroupNode = (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE*)((UINT8*)Iort +
+ NodesStartOffset);
+
+ while (NodeCount-- != 0) {
+ // Populate the node header
+ ItsGroupNode->Node.Type = EFI_ACPI_IORT_TYPE_ITS_GROUP;
+ ItsGroupNode->Node.Length = GetItsGroupNodeSize (NodeList);
+ ItsGroupNode->Node.Revision = 0;
+ ItsGroupNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
+ ItsGroupNode->Node.NumIdMappings = 0;
+ ItsGroupNode->Node.IdReference = 0;
+
+ // IORT specific data
+ ItsGroupNode->NumItsIdentifiers = NodeList->ItsIdCount;
+ ItsIds = (UINT32*)((UINT8*)ItsGroupNode +
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE));
+
+ Status = GetEArmObjGicItsIdentifierArray (
+ CfgMgrProtocol,
+ NodeList->ItsIdToken,
+ &ItsIdentifier,
+ &ItsIdentifierCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to get ITS Identifier array. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ if (ItsIdentifierCount < ItsGroupNode->NumItsIdentifiers) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to get the required number of ITS Identifiers.\n"
+ ));
+ return EFI_NOT_FOUND;
+ }
+
+ // Populate the ITS identifier array
+ for (IdIndex = 0; IdIndex < ItsGroupNode->NumItsIdentifiers; IdIndex++) {
+ ItsIds[IdIndex] = ItsIdentifier[IdIndex].ItsId;
+ } // ITS identifier array
+
+ // Next IORT Group Node
+ ItsGroupNode = (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE*)((UINT8*)ItsGroupNode +
+ ItsGroupNode->Node.Length);
+ NodeList++;
+ } // IORT Group Node
+
+ return EFI_SUCCESS;
+}
+
+/** Update the Named Component Node Information.
+
+ This function updates the Named Component node information in the IORT
+ table.
+
+ @param [in] This Pointer to the table Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Iort Pointer to IORT table structure.
+ @param [in] NodesStartOffset Offset for the start of the Named
+ Component Nodes.
+ @param [in] NodeList Pointer to an array of Named Component
+ Node Objects.
+ @param [in] NodeCount Number of Named Component Node Objects.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+**/
+STATIC
+EFI_STATUS
+AddNamedComponentNodes (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort,
+ IN CONST UINT32 NodesStartOffset,
+ IN CONST CM_ARM_NAMED_COMPONENT_NODE * NodeList,
+ IN UINT32 NodeCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE * NcNode;
+ EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;
+ UINT32 ObjectNameLenght;
+ CHAR8 * ObjectName;
+
+ ASSERT (Iort != NULL);
+
+ NcNode = (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE*)((UINT8*)Iort +
+ NodesStartOffset);
+
+ while (NodeCount-- != 0) {
+ // Populate the node header
+ NcNode->Node.Type = EFI_ACPI_IORT_TYPE_NAMED_COMP;
+ NcNode->Node.Length =
+ GetNamedComponentNodeSize (NodeList);
+ NcNode->Node.Revision = 2;
+ NcNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
+ NcNode->Node.NumIdMappings = NodeList->IdMappingCount;
+
+ ObjectNameLenght = AsciiStrLen (NodeList->ObjectName) + 1;
+ NcNode->Node.IdReference =
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE) +
+ (ALIGN_VALUE (ObjectNameLenght, 4));
+
+ // Named Component specific data
+ NcNode->Flags = NodeList->Flags;
+ NcNode->CacheCoherent = NodeList->CacheCoherent;
+ NcNode->AllocationHints = NodeList->AllocationHints;
+ NcNode->Reserved = EFI_ACPI_RESERVED_WORD;
+ NcNode->MemoryAccessFlags = NodeList->MemoryAccessFlags;
+ NcNode->AddressSizeLimit = NodeList->AddressSizeLimit;
+
+ // Copy the object name
+ ObjectName = (CHAR8*)((UINT8*)NcNode +
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE));
+ Status = AsciiStrCpyS (
+ ObjectName,
+ ObjectNameLenght,
+ NodeList->ObjectName
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to copy Object Name. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ if ((NodeList->IdMappingCount > 0) &&
+ (NodeList->IdMappingToken != CM_NULL_TOKEN)) {
+ // Ids for Named Component
+ IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)NcNode +
+ NcNode->Node.IdReference);
+
+ Status = AddIdMappingArray (
+ This,
+ CfgMgrProtocol,
+ IdMapArray,
+ NodeList->IdMappingCount,
+ NodeList->IdMappingToken
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ // Next Named Component Node
+ NcNode = (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE*)((UINT8*)NcNode +
+ NcNode->Node.Length);
+ NodeList++;
+ } // Named Component Node
+
+ return EFI_SUCCESS;
+}
+
+/** Update the Root Complex Node Information.
+
+ This function updates the Root Complex node information in the IORT table.
+
+ @param [in] This Pointer to the table Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Iort Pointer to IORT table structure.
+ @param [in] NodesStartOffset Offset for the start of the Root Complex
+ Nodes.
+ @param [in] NodeList Pointer to an array of Root Complex Node
+ Objects.
+ @param [in] NodeCount Number of Root Complex Node Objects.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+**/
+STATIC
+EFI_STATUS
+AddRootComplexNodes (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort,
+ IN CONST UINT32 NodesStartOffset,
+ IN CONST CM_ARM_ROOT_COMPLEX_NODE * NodeList,
+ IN UINT32 NodeCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_6_0_IO_REMAPPING_RC_NODE * RcNode;
+ EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;
+
+ ASSERT (Iort != NULL);
+
+ RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE*)((UINT8*)Iort +
+ NodesStartOffset);
+
+ while (NodeCount-- != 0) {
+ // Populate the node header
+ RcNode->Node.Type = EFI_ACPI_IORT_TYPE_ROOT_COMPLEX;
+ RcNode->Node.Length = GetRootComplexNodeSize (NodeList);
+ RcNode->Node.Revision = 1;
+ RcNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
+ RcNode->Node.NumIdMappings = NodeList->IdMappingCount;
+ RcNode->Node.IdReference = sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE);
+
+ // Root Complex specific data
+ RcNode->CacheCoherent = NodeList->CacheCoherent;
+ RcNode->AllocationHints = NodeList->AllocationHints;
+ RcNode->Reserved = EFI_ACPI_RESERVED_WORD;
+ RcNode->MemoryAccessFlags = NodeList->MemoryAccessFlags;
+ RcNode->AtsAttribute = NodeList->AtsAttribute;
+ RcNode->PciSegmentNumber = NodeList->PciSegmentNumber;
+ RcNode->MemoryAddressSize = NodeList->MemoryAddressSize;
+ RcNode->Reserved1[0] = EFI_ACPI_RESERVED_BYTE;
+ RcNode->Reserved1[1] = EFI_ACPI_RESERVED_BYTE;
+ RcNode->Reserved1[2] = EFI_ACPI_RESERVED_BYTE;
+
+ if ((NodeList->IdMappingCount > 0) &&
+ (NodeList->IdMappingToken != CM_NULL_TOKEN)) {
+ // Ids for Root Complex
+ IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)RcNode +
+ RcNode->Node.IdReference);
+ Status = AddIdMappingArray (
+ This,
+ CfgMgrProtocol,
+ IdMapArray,
+ NodeList->IdMappingCount,
+ NodeList->IdMappingToken
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ // Next Root Complex Node
+ RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE*)((UINT8*)RcNode +
+ RcNode->Node.Length);
+ NodeList++;
+ } // Root Complex Node
+
+ return EFI_SUCCESS;
+}
+
+/** Update the SMMU Interrupt Array.
+
+ This function retrieves the InterruptArray object referenced by the
+ InterruptToken and updates the SMMU InterruptArray.
+
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in, out] InterruptArray Pointer to an array of Interrupts.
+ @param [in] InterruptCount Number of entries in the InterruptArray.
+ @param [in] InterruptToken Reference Token for retrieving the SMMU
+ InterruptArray object.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+**/
+STATIC
+EFI_STATUS
+AddSmmuInterrruptArray (
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN OUT EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT * InterruptArray,
+ IN UINT32 InterruptCount,
+ IN CONST CM_OBJECT_TOKEN InterruptToken
+ )
+{
+ EFI_STATUS Status;
+ CM_ARM_SMMU_INTERRUPT * SmmuInterrupt;
+ UINT32 SmmuInterruptCount;
+
+ ASSERT (InterruptArray != NULL);
+
+ // Get the SMMU Interrupt Array
+ Status = GetEArmObjSmmuInterruptArray (
+ CfgMgrProtocol,
+ InterruptToken,
+ &SmmuInterrupt,
+ &SmmuInterruptCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to get SMMU Interrupt array. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ if (SmmuInterruptCount < InterruptCount) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to get the required number of SMMU Interrupts.\n"
+ ));
+ return EFI_NOT_FOUND;
+ }
+
+ // Populate the Id Mapping array
+ while (InterruptCount-- != 0) {
+ InterruptArray->Interrupt = SmmuInterrupt->Interrupt;
+ InterruptArray->InterruptFlags = SmmuInterrupt->Flags;
+ InterruptArray++;
+ SmmuInterrupt++;
+ } // Id Mapping array
+
+ return EFI_SUCCESS;
+}
+
+/** Update the SMMU v1/v2 Node Information.
+
+ @param [in] This Pointer to the table Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Iort Pointer to IORT table structure.
+ @param [in] NodesStartOffset Offset for the start of the SMMU v1/v2
+ Nodes.
+ @param [in] NodeList Pointer to an array of SMMU v1/v2 Node
+ Objects.
+ @param [in] NodeCount Number of SMMU v1/v2 Node Objects.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+**/
+STATIC
+EFI_STATUS
+AddSmmuV1V2Nodes (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort,
+ IN CONST UINT32 NodesStartOffset,
+ IN CONST CM_ARM_SMMUV1_SMMUV2_NODE * NodeList,
+ IN UINT32 NodeCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE * SmmuNode;
+ EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;
+
+ EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT * ContextInterruptArray;
+ EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT * PmuInterruptArray;
+
+ ASSERT (Iort != NULL);
+
+ SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE*)((UINT8*)Iort +
+ NodesStartOffset);
+
+ while (NodeCount-- != 0) {
+ // Populate the node header
+ SmmuNode->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv1v2;
+ SmmuNode->Node.Length = GetSmmuV1V2NodeSize (NodeList);
+ SmmuNode->Node.Revision = 0;
+ SmmuNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
+ SmmuNode->Node.NumIdMappings = NodeList->IdMappingCount;
+ SmmuNode->Node.IdReference = sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE) +
+ (NodeList->ContextInterruptCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)) +
+ (NodeList->PmuInterruptCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));
+
+ // SMMU v1/v2 specific data
+ SmmuNode->Base = NodeList->BaseAddress;
+ SmmuNode->Span = NodeList->Span;
+ SmmuNode->Model = NodeList->Model;
+ SmmuNode->Flags = NodeList->Flags;
+
+ // Reference to Global Interrupt Array
+ SmmuNode->GlobalInterruptArrayRef =
+ OFFSET_OF (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE, SMMU_NSgIrpt);
+
+ // Context Interrupt
+ SmmuNode->NumContextInterrupts = NodeList->ContextInterruptCount;
+ SmmuNode->ContextInterruptArrayRef =
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE);
+ ContextInterruptArray =
+ (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT*)((UINT8*)SmmuNode +
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE));
+
+ // PMU Interrupt
+ SmmuNode->NumPmuInterrupts = NodeList->PmuInterruptCount;
+ SmmuNode->PmuInterruptArrayRef = SmmuNode->ContextInterruptArrayRef +
+ (NodeList->ContextInterruptCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));
+ PmuInterruptArray =
+ (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT*)((UINT8*)SmmuNode +
+ SmmuNode->PmuInterruptArrayRef);
+
+ SmmuNode->SMMU_NSgIrpt = NodeList->SMMU_NSgIrpt;
+ SmmuNode->SMMU_NSgIrptFlags = NodeList->SMMU_NSgIrptFlags;
+ SmmuNode->SMMU_NSgCfgIrpt = NodeList->SMMU_NSgCfgIrpt;
+ SmmuNode->SMMU_NSgCfgIrptFlags = NodeList->SMMU_NSgCfgIrptFlags;
+
+ // Add Context Interrupt Array
+ Status = AddSmmuInterrruptArray (
+ CfgMgrProtocol,
+ ContextInterruptArray,
+ SmmuNode->NumContextInterrupts,
+ NodeList->ContextInterruptToken
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to Context Interrupt Array. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Add PMU Interrupt Array
+ if ((SmmuNode->NumPmuInterrupts > 0) &&
+ (NodeList->PmuInterruptToken != CM_NULL_TOKEN)) {
+ Status = AddSmmuInterrruptArray (
+ CfgMgrProtocol,
+ PmuInterruptArray,
+ SmmuNode->NumPmuInterrupts,
+ NodeList->PmuInterruptToken
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to PMU Interrupt Array. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ if ((NodeList->IdMappingCount > 0) &&
+ (NodeList->IdMappingToken != CM_NULL_TOKEN)) {
+ // Ids for SMMU v1/v2 Node
+ IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)SmmuNode +
+ SmmuNode->Node.IdReference);
+ Status = AddIdMappingArray (
+ This,
+ CfgMgrProtocol,
+ IdMapArray,
+ NodeList->IdMappingCount,
+ NodeList->IdMappingToken
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+ }
+ // Next SMMU v1/v2 Node
+ SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE*)((UINT8*)SmmuNode +
+ SmmuNode->Node.Length);
+ NodeList++;
+ } // SMMU v1/v2 Node
+
+ return EFI_SUCCESS;
+}
+
+/** Update the SMMUv3 Node Information.
+
+ This function updates the SMMUv3 node information in the IORT table.
+
+ @param [in] This Pointer to the table Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Iort Pointer to IORT table structure.
+ @param [in] NodesStartOffset Offset for the start of the SMMUv3 Nodes.
+ @param [in] NodeList Pointer to an array of SMMUv3 Node Objects.
+ @param [in] NodeCount Number of SMMUv3 Node Objects.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+**/
+STATIC
+EFI_STATUS
+AddSmmuV3Nodes (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort,
+ IN CONST UINT32 NodesStartOffset,
+ IN CONST CM_ARM_SMMUV3_NODE * NodeList,
+ IN UINT32 NodeCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE * SmmuV3Node;
+ EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;
+
+ ASSERT (Iort != NULL);
+
+ SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE*)((UINT8*)Iort +
+ NodesStartOffset);
+
+ while (NodeCount-- != 0) {
+ // Populate the node header
+ SmmuV3Node->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv3;
+ SmmuV3Node->Node.Length = GetSmmuV3NodeSize (NodeList);
+ SmmuV3Node->Node.Revision = 2;
+ SmmuV3Node->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
+ SmmuV3Node->Node.NumIdMappings = NodeList->IdMappingCount;
+ SmmuV3Node->Node.IdReference =
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE);
+
+ // SMMUv3 specific data
+ SmmuV3Node->Base = NodeList->BaseAddress;
+ SmmuV3Node->Flags = NodeList->Flags;
+ SmmuV3Node->Reserved = EFI_ACPI_RESERVED_WORD;
+ SmmuV3Node->VatosAddress = NodeList->VatosAddress;
+ SmmuV3Node->Model = NodeList->Model;
+ SmmuV3Node->Event = NodeList->EventInterrupt;
+ SmmuV3Node->Pri = NodeList->PriInterrupt;
+ SmmuV3Node->Gerr = NodeList->GerrInterrupt;
+ SmmuV3Node->Sync = NodeList->SyncInterrupt;
+
+ if ((SmmuV3Node->Flags & EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN) != 0) {
+ // The Proximity Domain Valid flag is set to 1
+ SmmuV3Node->ProximityDomain = NodeList->ProximityDomain;
+ } else {
+ SmmuV3Node->ProximityDomain = 0;
+ }
+
+ if ((SmmuV3Node->Event != 0) && (SmmuV3Node->Pri != 0) &&
+ (SmmuV3Node->Gerr != 0) && (SmmuV3Node->Sync != 0)) {
+ // If all the SMMU control interrupts are GSIV based,
+ // the DeviceID mapping index field is ignored.
+ SmmuV3Node->DeviceIdMappingIndex = 0;
+ } else {
+ SmmuV3Node->DeviceIdMappingIndex = NodeList->DeviceIdMappingIndex;
+ }
+
+ if ((NodeList->IdMappingCount > 0) &&
+ (NodeList->IdMappingToken != CM_NULL_TOKEN)) {
+ // Ids for SMMUv3 node
+ IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)SmmuV3Node +
+ SmmuV3Node->Node.IdReference);
+ Status = AddIdMappingArray (
+ This,
+ CfgMgrProtocol,
+ IdMapArray,
+ NodeList->IdMappingCount,
+ NodeList->IdMappingToken
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ // Next SMMUv3 Node
+ SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE*)((UINT8*)SmmuV3Node +
+ SmmuV3Node->Node.Length);
+ NodeList++;
+ } // SMMUv3 Node
+
+ return EFI_SUCCESS;
+}
+
+/** Update the PMCG Node Information.
+
+ This function updates the PMCG node information in the IORT table.
+
+ @param [in] This Pointer to the table Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Iort Pointer to IORT table structure.
+ @param [in] NodesStartOffset Offset for the start of the PMCG Nodes.
+ @param [in] NodeList Pointer to an array of PMCG Node Objects.
+ @param [in] NodeCount Number of PMCG Node Objects.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+**/
+STATIC
+EFI_STATUS
+AddPmcgNodes (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort,
+ IN CONST UINT32 NodesStartOffset,
+ IN CONST CM_ARM_PMCG_NODE * NodeList,
+ IN UINT32 NodeCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE * PmcgNode;
+ EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;
+ ACPI_IORT_GENERATOR * Generator;
+
+ ASSERT (Iort != NULL);
+
+ Generator = (ACPI_IORT_GENERATOR*)This;
+ PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE*)((UINT8*)Iort +
+ NodesStartOffset);
+
+ while (NodeCount-- != 0) {
+ // Populate the node header
+ PmcgNode->Node.Type = EFI_ACPI_IORT_TYPE_PMCG;
+ PmcgNode->Node.Length = GetPmcgNodeSize (NodeList);
+ PmcgNode->Node.Revision = 1;
+ PmcgNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
+ PmcgNode->Node.NumIdMappings = NodeList->IdMappingCount;
+ PmcgNode->Node.IdReference = sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE);
+
+ // PMCG specific data
+ PmcgNode->Base = NodeList->BaseAddress;
+ PmcgNode->OverflowInterruptGsiv = NodeList->OverflowInterrupt;
+ PmcgNode->Page1Base = NodeList->Page1BaseAddress;
+
+ Status = GetNodeOffsetReferencedByToken (
+ Generator->NodeIndexer,
+ Generator->IortNodeCount,
+ NodeList->ReferenceToken,
+ &PmcgNode->NodeReference
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to get Output Reference for PMCG Node."
+ "Reference Token = %p"
+ " Status = %r\n",
+ NodeList->ReferenceToken,
+ Status
+ ));
+ return Status;
+ }
+
+ if ((NodeList->IdMappingCount > 0) &&
+ (NodeList->IdMappingToken != CM_NULL_TOKEN)) {
+ // Ids for PMCG node
+ IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)PmcgNode +
+ PmcgNode->Node.IdReference);
+
+ Status = AddIdMappingArray (
+ This,
+ CfgMgrProtocol,
+ IdMapArray,
+ NodeList->IdMappingCount,
+ NodeList->IdMappingToken
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ // Next PMCG Node
+ PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE*)((UINT8*)PmcgNode +
+ PmcgNode->Node.Length);
+ NodeList++;
+ } // PMCG Node
+
+ return EFI_SUCCESS;
+}
+
+/** Construct the IORT ACPI table.
+
+ This function invokes the Configuration Manager protocol interface
+ to get the required hardware information for generating the ACPI
+ table.
+
+ If this function allocates any resources then they must be freed
+ in the FreeXXXXTableResources function.
+
+ @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 [out] Table Pointer to the constructed ACPI Table.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
+ Manager is less than the Object size for the
+ requested object.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildIortTable (
+ 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
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TableSize;
+ UINT32 IortNodeCount;
+
+ UINT32 ItsGroupNodeCount;
+ UINT32 NamedComponentNodeCount;
+ UINT32 RootComplexNodeCount;
+ UINT32 SmmuV1V2NodeCount;
+ UINT32 SmmuV3NodeCount;
+ UINT32 PmcgNodeCount;
+
+ UINT32 ItsGroupOffset;
+ UINT32 NamedComponentOffset;
+ UINT32 RootComplexOffset;
+ UINT32 SmmuV1V2Offset;
+ UINT32 SmmuV3Offset;
+ UINT32 PmcgOffset;
+
+ CM_ARM_ITS_GROUP_NODE * ItsGroupNodeList;
+ CM_ARM_NAMED_COMPONENT_NODE * NamedComponentNodeList;
+ CM_ARM_ROOT_COMPLEX_NODE * RootComplexNodeList;
+ CM_ARM_SMMUV1_SMMUV2_NODE * SmmuV1V2NodeList;
+ CM_ARM_SMMUV3_NODE * SmmuV3NodeList;
+ CM_ARM_PMCG_NODE * PmcgNodeList;
+
+ EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort;
+ IORT_NODE_INDEXER * NodeIndexer;
+ ACPI_IORT_GENERATOR * Generator;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (Table != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Requested table revision = %d, is not supported."
+ "Supported table revision: Minimum = %d, Maximum = %d\n",
+ AcpiTableInfo->AcpiTableRevision,
+ This->MinAcpiTableRevision,
+ This->AcpiTableRevision
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Generator = (ACPI_IORT_GENERATOR*)This;
+ *Table = NULL;
+
+ // Get the ITS group node info
+ Status = GetEArmObjItsGroup (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &ItsGroupNodeList,
+ &ItsGroupNodeCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to get ITS Group Node Info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ // Add the ITS group node count
+ IortNodeCount = ItsGroupNodeCount;
+
+ // Get the Named component node info
+ Status = GetEArmObjNamedComponent (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &NamedComponentNodeList,
+ &NamedComponentNodeCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to get Named Component Node Info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ // Add the Named Component group count
+ IortNodeCount += NamedComponentNodeCount;
+
+ // Get the Root complex node info
+ Status = GetEArmObjRootComplex (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &RootComplexNodeList,
+ &RootComplexNodeCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to get Root Complex Node Info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ // Add the Root Complex node count
+ IortNodeCount += RootComplexNodeCount;
+
+ // Get the SMMU v1/v2 node info
+ Status = GetEArmObjSmmuV1SmmuV2 (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &SmmuV1V2NodeList,
+ &SmmuV1V2NodeCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to get SMMUv1/SMMUv2 Node Info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ // Add the SMMU v1/v2 node count
+ IortNodeCount += SmmuV1V2NodeCount;
+
+ // Get the SMMUv3 node info
+ Status = GetEArmObjSmmuV3 (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &SmmuV3NodeList,
+ &SmmuV3NodeCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to get SMMUv3 Node Info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ // Add the SMMUv3 node count
+ IortNodeCount += SmmuV3NodeCount;
+
+ // Get the PMCG node info
+ Status = GetEArmObjPmcg (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &PmcgNodeList,
+ &PmcgNodeCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to get PMCG Node Info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ // Add the PMCG node count
+ IortNodeCount += PmcgNodeCount;
+
+ // Allocate Node Indexer array
+ NodeIndexer = (IORT_NODE_INDEXER*)AllocateZeroPool (
+ (sizeof (IORT_NODE_INDEXER) *
+ IortNodeCount)
+ );
+ if (NodeIndexer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to allocate memory for Node Indexer" \
+ " Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ DEBUG ((DEBUG_INFO, "INFO: NodeIndexer = %p\n", NodeIndexer));
+ Generator->IortNodeCount = IortNodeCount;
+ Generator->NodeIndexer = NodeIndexer;
+
+ // Calculate the size of the IORT table
+ TableSize = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);
+
+ // ITS Group Nodes
+ if (ItsGroupNodeCount > 0) {
+ ItsGroupOffset = TableSize;
+ // Size of ITS Group node list.
+ TableSize += GetSizeofItsGroupNodes (
+ ItsGroupOffset,
+ ItsGroupNodeList,
+ ItsGroupNodeCount,
+ &NodeIndexer
+ );
+ }
+
+ // Named Component Nodes
+ if (NamedComponentNodeCount > 0) {
+ NamedComponentOffset = TableSize;
+ // Size of Named Component node list.
+ TableSize += GetSizeofNamedComponentNodes (
+ NamedComponentOffset,
+ NamedComponentNodeList,
+ NamedComponentNodeCount,
+ &NodeIndexer
+ );
+ }
+
+ // Root Complex Nodes
+ if (RootComplexNodeCount > 0) {
+ RootComplexOffset = TableSize;
+ // Size of Root Complex node list.
+ TableSize += GetSizeofRootComplexNodes (
+ RootComplexOffset,
+ RootComplexNodeList,
+ RootComplexNodeCount,
+ &NodeIndexer
+ );
+ }
+
+ // SMMUv1/SMMUv2 Nodes
+ if (SmmuV1V2NodeCount > 0) {
+ SmmuV1V2Offset = TableSize;
+ // Size of SMMUv1/SMMUv2 node list.
+ TableSize += GetSizeofSmmuV1V2Nodes (
+ SmmuV1V2Offset,
+ SmmuV1V2NodeList,
+ SmmuV1V2NodeCount,
+ &NodeIndexer
+ );
+ }
+
+ // SMMUv3 Nodes
+ if (SmmuV3NodeCount > 0) {
+ SmmuV3Offset = TableSize;
+ // Size of SMMUv3 node list.
+ TableSize += GetSizeofSmmuV3Nodes (
+ SmmuV3Offset,
+ SmmuV3NodeList,
+ SmmuV3NodeCount,
+ &NodeIndexer
+ );
+ }
+
+ // PMCG Nodes
+ if (PmcgNodeCount > 0) {
+ PmcgOffset = TableSize;
+ // Size of PMCG node list.
+ TableSize += GetSizeofPmcgNodes (
+ PmcgOffset,
+ PmcgNodeList,
+ PmcgNodeCount,
+ &NodeIndexer
+ );
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "INFO: IORT:\n" \
+ " IortNodeCount = %d\n" \
+ " TableSize = %d\n",
+ IortNodeCount,
+ TableSize
+ ));
+
+ DEBUG ((
+ DEBUG_INFO,
+ " ItsGroupNodeCount = %d\n" \
+ " ItsGroupOffset = %d\n",
+ ItsGroupNodeCount,
+ ItsGroupOffset
+ ));
+
+ DEBUG ((
+ DEBUG_INFO,
+ " NamedComponentNodeCount = %d\n" \
+ " NamedComponentOffset = %d\n",
+ NamedComponentNodeCount,
+ NamedComponentOffset
+ ));
+
+ DEBUG ((
+ DEBUG_INFO,
+ " RootComplexNodeCount = %d\n" \
+ " RootComplexOffset = %d\n",
+ RootComplexNodeCount,
+ RootComplexOffset
+ ));
+
+ DEBUG ((
+ DEBUG_INFO,
+ " SmmuV1V2NodeCount = %d\n" \
+ " SmmuV1V2Offset = %d\n",
+ SmmuV1V2NodeCount,
+ SmmuV1V2Offset
+ ));
+
+ DEBUG ((
+ DEBUG_INFO,
+ " SmmuV3NodeCount = %d\n" \
+ " SmmuV3Offset = %d\n",
+ SmmuV3NodeCount,
+ SmmuV3Offset
+ ));
+
+ DEBUG ((
+ DEBUG_INFO,
+ " PmcgNodeCount = %d\n" \
+ " PmcgOffset = %d\n",
+ PmcgNodeCount,
+ PmcgOffset
+ ));
+
+ // Allocate the Buffer for IORT table
+ *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);
+ if (*Table == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to allocate memory for IORT Table, Size = %d," \
+ " Status = %r\n",
+ TableSize,
+ Status
+ ));
+ goto error_handler;
+ }
+
+ Iort = (EFI_ACPI_6_0_IO_REMAPPING_TABLE*)*Table;
+
+ DEBUG ((
+ DEBUG_INFO,
+ "IORT: Iort = 0x%p TableSize = 0x%x\n",
+ Iort,
+ TableSize
+ ));
+
+ Status = AddAcpiHeader (
+ CfgMgrProtocol,
+ This,
+ &Iort->Header,
+ AcpiTableInfo->AcpiTableRevision,
+ TableSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to add ACPI header. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ // Update IORT table
+ Iort->NumNodes = IortNodeCount;
+ Iort->NodeOffset = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);
+ Iort->Reserved = EFI_ACPI_RESERVED_DWORD;
+
+ if (ItsGroupNodeCount > 0) {
+ Status = AddItsGroupNodes (
+ This,
+ CfgMgrProtocol,
+ Iort,
+ ItsGroupOffset,
+ ItsGroupNodeList,
+ ItsGroupNodeCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to add ITS Group Node. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ if (NamedComponentNodeCount > 0) {
+ Status = AddNamedComponentNodes (
+ This,
+ CfgMgrProtocol,
+ Iort,
+ NamedComponentOffset,
+ NamedComponentNodeList,
+ NamedComponentNodeCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to add Named Component Node. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ if (RootComplexNodeCount > 0) {
+ Status = AddRootComplexNodes (
+ This,
+ CfgMgrProtocol,
+ Iort,
+ RootComplexOffset,
+ RootComplexNodeList,
+ RootComplexNodeCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to add Root Complex Node. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ if (SmmuV1V2NodeCount > 0) {
+ Status = AddSmmuV1V2Nodes (
+ This,
+ CfgMgrProtocol,
+ Iort,
+ SmmuV1V2Offset,
+ SmmuV1V2NodeList,
+ SmmuV1V2NodeCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to add SMMU v1/v2 Node. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ if (SmmuV3NodeCount > 0) {
+ Status = AddSmmuV3Nodes (
+ This,
+ CfgMgrProtocol,
+ Iort,
+ SmmuV3Offset,
+ SmmuV3NodeList,
+ SmmuV3NodeCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ if (PmcgNodeCount > 0) {
+ Status = AddPmcgNodes (
+ This,
+ CfgMgrProtocol,
+ Iort,
+ PmcgOffset,
+ PmcgNodeList,
+ PmcgNodeCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ return EFI_SUCCESS;
+
+error_handler:
+ if (Generator->NodeIndexer != NULL) {
+ FreePool (Generator->NodeIndexer);
+ Generator->NodeIndexer = NULL;
+ }
+
+ if (*Table != NULL) {
+ FreePool (*Table);
+ *Table = NULL;
+ }
+ return Status;
+}
+
+/** Free any resources allocated for constructing the IORT
+
+ @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, out] Table Pointer to the ACPI Table.
+
+ @retval EFI_SUCCESS The resources were freed successfully.
+ @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
+**/
+STATIC
+EFI_STATUS
+FreeIortTableResources (
+ 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
+ )
+{
+ ACPI_IORT_GENERATOR * Generator;
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ Generator = (ACPI_IORT_GENERATOR*)This;
+
+ // Free any memory allocated by the generator
+ if (Generator->NodeIndexer != NULL) {
+ FreePool (Generator->NodeIndexer);
+ Generator->NodeIndexer = NULL;
+ }
+
+ if ((Table == NULL) || (*Table == NULL)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: IORT: Invalid Table Pointer\n"));
+ ASSERT ((Table != NULL) && (*Table != NULL));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FreePool (*Table);
+ *Table = NULL;
+ return EFI_SUCCESS;
+}
+
+/** The IORT Table Generator revision.
+*/
+#define IORT_GENERATOR_REVISION CREATE_REVISION (1, 0)
+
+/** The interface for the MADT Table Generator.
+*/
+STATIC
+ACPI_IORT_GENERATOR IortGenerator = {
+ // ACPI table generator header
+ {
+ // Generator ID
+ CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdIort),
+ // Generator Description
+ L"ACPI.STD.IORT.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE,
+ // ACPI Table Revision supported by this Generator
+ EFI_ACPI_IO_REMAPPING_TABLE_REVISION,
+ // Minimum supported ACPI Table Revision
+ EFI_ACPI_IO_REMAPPING_TABLE_REVISION,
+ // Creator ID
+ TABLE_GENERATOR_CREATOR_ID_ARM,
+ // Creator Revision
+ IORT_GENERATOR_REVISION,
+ // Build Table function
+ BuildIortTable,
+ // Free Resource function
+ FreeIortTableResources,
+ // Extended build function not needed
+ NULL,
+ // Extended build function not implemented by the generator.
+ // Hence extended free resource function is not required.
+ NULL
+ },
+
+ // IORT Generator private data
+
+ // Iort Node count
+ 0,
+ // Pointer to Iort node indexer
+ NULL
+};
+
+/** Register the Generator with the ACPI Table Factory.
+
+ @param [in] ImageHandle The handle to the image.
+ @param [in] SystemTable Pointer to the System Table.
+
+ @retval EFI_SUCCESS The Generator is registered.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_ALREADY_STARTED The Generator for the Table ID
+ is already registered.
+**/
+EFI_STATUS
+EFIAPI
+AcpiIortLibConstructor (
+ IN CONST EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * CONST SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = RegisterAcpiTableGenerator (&IortGenerator.Header);
+ DEBUG ((DEBUG_INFO, "IORT: Register Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/** Deregister the Generator from the ACPI Table Factory.
+
+ @param [in] ImageHandle The handle to the image.
+ @param [in] SystemTable Pointer to the System Table.
+
+ @retval EFI_SUCCESS The Generator is deregistered.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The Generator is not registered.
+**/
+EFI_STATUS
+EFIAPI
+AcpiIortLibDestructor (
+ IN CONST EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * CONST SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&IortGenerator.Header);
+ DEBUG ((DEBUG_INFO, "Iort: Deregister Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.h b/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.h
new file mode 100644
index 0000000000..44c89042e2
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.h
@@ -0,0 +1,50 @@
+/** @file
+
+ Copyright (c) 2018, ARM Limited. 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.
+
+ @par Glossary:
+ - Cm or CM - Configuration Manager
+ - Obj or OBJ - Object
+ - Std or STD - Standard
+**/
+
+#ifndef IORT_GENERATOR_H_
+#define IORT_GENERATOR_H_
+
+#pragma pack(1)
+
+/** A structure that describes the Node indexer
+ used for indexing the IORT nodes.
+*/
+typedef struct IortNodeIndexer {
+ /// Index token for the Node
+ CM_OBJECT_TOKEN Token;
+ /// Pointer to the node
+ VOID * Object;
+ /// Node offset from the start of the IORT table
+ UINT32 Offset;
+} IORT_NODE_INDEXER;
+
+typedef struct AcpiIortGenerator {
+ /// ACPI Table generator header
+ ACPI_TABLE_GENERATOR Header;
+
+ // IORT Generator private data
+
+ /// IORT node count
+ UINT32 IortNodeCount;
+ /// Pointer to the node indexer array
+ IORT_NODE_INDEXER * NodeIndexer;
+} ACPI_IORT_GENERATOR;
+
+#pragma pack()
+
+#endif // IORT_GENERATOR_H_