--- /dev/null
+/** @file\r
+ IORT Table Generator\r
+\r
+ Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+ @par Reference(s):\r
+ - IO Remapping Table, Platform Design Document,\r
+ Document number: ARM DEN 0049D, Issue D, March 2018\r
+\r
+**/\r
+\r
+#include <IndustryStandard/IoRemappingTable.h>\r
+#include <Library/AcpiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Protocol/AcpiTable.h>\r
+\r
+// Module specific include files.\r
+#include <AcpiTableGenerator.h>\r
+#include <ConfigurationManagerObject.h>\r
+#include <ConfigurationManagerHelper.h>\r
+#include <Library/TableHelperLib.h>\r
+#include <Protocol/ConfigurationManagerProtocol.h>\r
+\r
+#include "IortGenerator.h"\r
+\r
+/** ARM standard IORT Generator\r
+\r
+Requirements:\r
+ The following Configuration Manager Object(s) are required by\r
+ this Generator:\r
+ - EArmObjItsGroup\r
+ - EArmObjNamedComponent\r
+ - EArmObjRootComplex\r
+ - EArmObjSmmuV1SmmuV2\r
+ - EArmObjSmmuV3\r
+ - EArmObjPmcg\r
+ - EArmObjGicItsIdentifierArray\r
+ - EArmObjIdMapping\r
+ - EArmObjGicItsIdentifierArray\r
+*/\r
+\r
+/** This macro expands to a function that retrieves the ITS\r
+ Group node information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjItsGroup,\r
+ CM_ARM_ITS_GROUP_NODE\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the\r
+ Named Component node information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjNamedComponent,\r
+ CM_ARM_NAMED_COMPONENT_NODE\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the\r
+ Root Complex node information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjRootComplex,\r
+ CM_ARM_ROOT_COMPLEX_NODE\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the\r
+ SMMU v1/v2 node information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjSmmuV1SmmuV2,\r
+ CM_ARM_SMMUV1_SMMUV2_NODE\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the\r
+ SMMU v3 node information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjSmmuV3,\r
+ CM_ARM_SMMUV3_NODE\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the\r
+ PMCG node information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjPmcg,\r
+ CM_ARM_PMCG_NODE\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the\r
+ ITS Identifier Array information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjGicItsIdentifierArray,\r
+ CM_ARM_ITS_IDENTIFIER\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the\r
+ Id Mapping Array information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjIdMapping,\r
+ CM_ARM_ID_MAPPING\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the\r
+ SMMU Interrupt Array information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjSmmuInterruptArray,\r
+ CM_ARM_SMMU_INTERRUPT\r
+ );\r
+\r
+/** Returns the size of the ITS Group node.\r
+\r
+ @param [in] Node Pointer to ITS Group node.\r
+\r
+ @retval Size of the ITS Group Node.\r
+**/\r
+STATIC\r
+UINT32\r
+GetItsGroupNodeSize (\r
+ IN CONST CM_ARM_ITS_GROUP_NODE * Node\r
+ )\r
+{\r
+ ASSERT (Node != NULL);\r
+\r
+ /* Size of ITS Group Node +\r
+ Size of ITS Identifier array\r
+ */\r
+ return sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE) +\r
+ (Node->ItsIdCount * sizeof (UINT32));\r
+}\r
+\r
+/** Returns the total size required for the ITS Group nodes and\r
+ updates the Node Indexer.\r
+\r
+ This function calculates the size required for the node group\r
+ and also populates the Node Indexer array with offsets for the\r
+ individual nodes.\r
+\r
+ @param [in] NodeStartOffset Offset from the start of the\r
+ IORT where this node group starts.\r
+ @param [in] NodeList Pointer to ITS Group node list.\r
+ @param [in] NodeCount Count of the ITS Group nodes.\r
+ @param [in, out] NodeIndexer Pointer to the next Node Indexer.\r
+\r
+ @retval Total size of the ITS Group Nodes.\r
+**/\r
+STATIC\r
+UINT32\r
+GetSizeofItsGroupNodes (\r
+ IN CONST UINT32 NodeStartOffset,\r
+ IN CONST CM_ARM_ITS_GROUP_NODE * NodeList,\r
+ IN UINT32 NodeCount,\r
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer\r
+ )\r
+{\r
+ UINT32 Size;\r
+\r
+ ASSERT (NodeList != NULL);\r
+\r
+ Size = 0;\r
+ while (NodeCount-- != 0) {\r
+ (*NodeIndexer)->Token = NodeList->Token;\r
+ (*NodeIndexer)->Object = (VOID*)NodeList;\r
+ (*NodeIndexer)->Offset = Size + NodeStartOffset;\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",\r
+ *NodeIndexer,\r
+ (*NodeIndexer)->Token,\r
+ (*NodeIndexer)->Object,\r
+ (*NodeIndexer)->Offset\r
+ ));\r
+\r
+ Size += GetItsGroupNodeSize (NodeList);\r
+ (*NodeIndexer)++;\r
+ NodeList++;\r
+ }\r
+ return Size;\r
+}\r
+\r
+/** Returns the size of the Named Component node.\r
+\r
+ @param [in] Node Pointer to Named Component node.\r
+\r
+ @retval Size of the Named Component node.\r
+**/\r
+STATIC\r
+UINT32\r
+GetNamedComponentNodeSize (\r
+ IN CONST CM_ARM_NAMED_COMPONENT_NODE * Node\r
+ )\r
+{\r
+ ASSERT (Node != NULL);\r
+\r
+ /* Size of Named Component node +\r
+ Size of ID mapping array +\r
+ Size of ASCII string + 'padding to 32-bit word aligned'.\r
+ */\r
+ return sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE) +\r
+ (Node->IdMappingCount *\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) +\r
+ ALIGN_VALUE (AsciiStrSize (Node->ObjectName), 4);\r
+}\r
+\r
+/** Returns the total size required for the Named Component nodes and\r
+ updates the Node Indexer.\r
+\r
+ This function calculates the size required for the node group\r
+ and also populates the Node Indexer array with offsets for the\r
+ individual nodes.\r
+\r
+ @param [in] NodeStartOffset Offset from the start of the\r
+ IORT where this node group starts.\r
+ @param [in] NodeList Pointer to Named Component node list.\r
+ @param [in] NodeCount Count of the Named Component nodes.\r
+ @param [in, out] NodeIndexer Pointer to the next Node Indexer.\r
+\r
+ @retval Total size of the Named Component nodes.\r
+**/\r
+STATIC\r
+UINT32\r
+GetSizeofNamedComponentNodes (\r
+ IN CONST UINT32 NodeStartOffset,\r
+ IN CONST CM_ARM_NAMED_COMPONENT_NODE * NodeList,\r
+ IN UINT32 NodeCount,\r
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer\r
+ )\r
+{\r
+ UINT32 Size;\r
+\r
+ ASSERT (NodeList != NULL);\r
+\r
+ Size = 0;\r
+ while (NodeCount-- != 0) {\r
+ (*NodeIndexer)->Token = NodeList->Token;\r
+ (*NodeIndexer)->Object = (VOID*)NodeList;\r
+ (*NodeIndexer)->Offset = Size + NodeStartOffset;\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",\r
+ *NodeIndexer,\r
+ (*NodeIndexer)->Token,\r
+ (*NodeIndexer)->Object,\r
+ (*NodeIndexer)->Offset\r
+ ));\r
+\r
+ Size += GetNamedComponentNodeSize (NodeList);\r
+ (*NodeIndexer)++;\r
+ NodeList++;\r
+ }\r
+\r
+ return Size;\r
+}\r
+\r
+/** Returns the size of the Root Complex node.\r
+\r
+ @param [in] Node Pointer to Root Complex node.\r
+\r
+ @retval Size of the Root Complex node.\r
+**/\r
+STATIC\r
+UINT32\r
+GetRootComplexNodeSize (\r
+ IN CONST CM_ARM_ROOT_COMPLEX_NODE * Node\r
+ )\r
+{\r
+ ASSERT (Node != NULL);\r
+\r
+ /* Size of Root Complex node +\r
+ Size of ID mapping array\r
+ */\r
+ return sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE) +\r
+ (Node->IdMappingCount *\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE));\r
+}\r
+\r
+/** Returns the total size required for the Root Complex nodes and\r
+ updates the Node Indexer.\r
+\r
+ This function calculates the size required for the node group\r
+ and also populates the Node Indexer array with offsets for the\r
+ individual nodes.\r
+\r
+ @param [in] NodeStartOffset Offset from the start of the\r
+ IORT where this node group starts.\r
+ @param [in] NodeList Pointer to Root Complex node list.\r
+ @param [in] NodeCount Count of the Root Complex nodes.\r
+ @param [in, out] NodeIndexer Pointer to the next Node Indexer.\r
+\r
+ @retval Total size of the Root Complex nodes.\r
+**/\r
+STATIC\r
+UINT32\r
+GetSizeofRootComplexNodes (\r
+ IN CONST UINT32 NodeStartOffset,\r
+ IN CONST CM_ARM_ROOT_COMPLEX_NODE * NodeList,\r
+ IN UINT32 NodeCount,\r
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer\r
+ )\r
+{\r
+ UINT32 Size;\r
+\r
+ ASSERT (NodeList != NULL);\r
+\r
+ Size = 0;\r
+ while (NodeCount-- != 0) {\r
+ (*NodeIndexer)->Token = NodeList->Token;\r
+ (*NodeIndexer)->Object = (VOID*)NodeList;\r
+ (*NodeIndexer)->Offset = Size + NodeStartOffset;\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",\r
+ *NodeIndexer,\r
+ (*NodeIndexer)->Token,\r
+ (*NodeIndexer)->Object,\r
+ (*NodeIndexer)->Offset\r
+ ));\r
+\r
+ Size += GetRootComplexNodeSize (NodeList);\r
+ (*NodeIndexer)++;\r
+ NodeList++;\r
+ }\r
+\r
+ return Size;\r
+}\r
+\r
+/** Returns the size of the SMMUv1/SMMUv2 node.\r
+\r
+ @param [in] Node Pointer to SMMUv1/SMMUv2 node list.\r
+\r
+ @retval Size of the SMMUv1/SMMUv2 node.\r
+**/\r
+STATIC\r
+UINT32\r
+GetSmmuV1V2NodeSize (\r
+ IN CONST CM_ARM_SMMUV1_SMMUV2_NODE * Node\r
+ )\r
+{\r
+ ASSERT (Node != NULL);\r
+\r
+ /* Size of SMMU v1/SMMU v2 node +\r
+ Size of ID mapping array +\r
+ Size of context interrupt array +\r
+ Size of PMU interrupt array\r
+ */\r
+ return sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE) +\r
+ (Node->IdMappingCount *\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) +\r
+ (Node->ContextInterruptCount *\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)) +\r
+ (Node->PmuInterruptCount *\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));\r
+}\r
+\r
+/** Returns the total size required for the SMMUv1/SMMUv2 nodes and\r
+ updates the Node Indexer.\r
+\r
+ This function calculates the size required for the node group\r
+ and also populates the Node Indexer array with offsets for the\r
+ individual nodes.\r
+\r
+ @param [in] NodeStartOffset Offset from the start of the\r
+ IORT where this node group starts.\r
+ @param [in] NodeList Pointer to SMMUv1/SMMUv2 node list.\r
+ @param [in] NodeCount Count of the SMMUv1/SMMUv2 nodes.\r
+ @param [in, out] NodeIndexer Pointer to the next Node Indexer.\r
+\r
+ @retval Total size of the SMMUv1/SMMUv2 nodes.\r
+**/\r
+STATIC\r
+UINT32\r
+GetSizeofSmmuV1V2Nodes (\r
+ IN CONST UINT32 NodeStartOffset,\r
+ IN CONST CM_ARM_SMMUV1_SMMUV2_NODE * NodeList,\r
+ IN UINT32 NodeCount,\r
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer\r
+ )\r
+{\r
+ UINT32 Size;\r
+\r
+ ASSERT (NodeList != NULL);\r
+\r
+ Size = 0;\r
+ while (NodeCount-- != 0) {\r
+ (*NodeIndexer)->Token = NodeList->Token;\r
+ (*NodeIndexer)->Object = (VOID*)NodeList;\r
+ (*NodeIndexer)->Offset = Size + NodeStartOffset;\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",\r
+ *NodeIndexer,\r
+ (*NodeIndexer)->Token,\r
+ (*NodeIndexer)->Object,\r
+ (*NodeIndexer)->Offset\r
+ ));\r
+\r
+ Size += GetSmmuV1V2NodeSize (NodeList);\r
+ (*NodeIndexer)++;\r
+ NodeList++;\r
+ }\r
+ return Size;\r
+}\r
+\r
+/** Returns the size of the SMMUv3 node.\r
+\r
+ @param [in] Node Pointer to SMMUv3 node list.\r
+\r
+ @retval Total size of the SMMUv3 nodes.\r
+**/\r
+STATIC\r
+UINT32\r
+GetSmmuV3NodeSize (\r
+ IN CONST CM_ARM_SMMUV3_NODE * Node\r
+ )\r
+{\r
+ ASSERT (Node != NULL);\r
+\r
+ /* Size of SMMU v1/SMMU v2 node +\r
+ Size of ID mapping array\r
+ */\r
+ return sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE) +\r
+ (Node->IdMappingCount *\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE));\r
+}\r
+\r
+/** Returns the total size required for the SMMUv3 nodes and\r
+ updates the Node Indexer.\r
+\r
+ This function calculates the size required for the node group\r
+ and also populates the Node Indexer array with offsets for the\r
+ individual nodes.\r
+\r
+ @param [in] NodeStartOffset Offset from the start of the\r
+ IORT where this node group starts.\r
+ @param [in] NodeList Pointer to SMMUv3 node list.\r
+ @param [in] NodeCount Count of the SMMUv3 nodes.\r
+ @param [in, out] NodeIndexer Pointer to the next Node Indexer.\r
+\r
+ @retval Total size of the SMMUv3 nodes.\r
+**/\r
+STATIC\r
+UINT32\r
+GetSizeofSmmuV3Nodes (\r
+ IN CONST UINT32 NodeStartOffset,\r
+ IN CONST CM_ARM_SMMUV3_NODE * NodeList,\r
+ IN UINT32 NodeCount,\r
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer\r
+ )\r
+{\r
+ UINT32 Size;\r
+\r
+ ASSERT (NodeList != NULL);\r
+\r
+ Size = 0;\r
+ while (NodeCount-- != 0) {\r
+ (*NodeIndexer)->Token = NodeList->Token;\r
+ (*NodeIndexer)->Object = (VOID*)NodeList;\r
+ (*NodeIndexer)->Offset = Size + NodeStartOffset;\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",\r
+ *NodeIndexer,\r
+ (*NodeIndexer)->Token,\r
+ (*NodeIndexer)->Object,\r
+ (*NodeIndexer)->Offset\r
+ ));\r
+\r
+ Size += GetSmmuV3NodeSize (NodeList);\r
+ (*NodeIndexer)++;\r
+ NodeList++;\r
+ }\r
+ return Size;\r
+}\r
+\r
+/** Returns the size of the PMCG node.\r
+\r
+ @param [in] Node Pointer to PMCG node.\r
+\r
+ @retval Size of the PMCG node.\r
+**/\r
+STATIC\r
+UINT32\r
+GetPmcgNodeSize (\r
+ IN CONST CM_ARM_PMCG_NODE * Node\r
+ )\r
+{\r
+ ASSERT (Node != NULL);\r
+\r
+ /* Size of PMCG node +\r
+ Size of ID mapping array\r
+ */\r
+ return sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE) +\r
+ (Node->IdMappingCount *\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE));\r
+}\r
+\r
+/** Returns the total size required for the PMCG nodes and\r
+ updates the Node Indexer.\r
+\r
+ This function calculates the size required for the node group\r
+ and also populates the Node Indexer array with offsets for the\r
+ individual nodes.\r
+\r
+ @param [in] NodeStartOffset Offset from the start of the\r
+ IORT where this node group starts.\r
+ @param [in] NodeList Pointer to PMCG node list.\r
+ @param [in] NodeCount Count of the PMCG nodes.\r
+ @param [in, out] NodeIndexer Pointer to the next Node Indexer.\r
+\r
+ @retval Total size of the PMCG nodes.\r
+**/\r
+STATIC\r
+UINT32\r
+GetSizeofPmcgNodes (\r
+ IN CONST UINT32 NodeStartOffset,\r
+ IN CONST CM_ARM_PMCG_NODE * NodeList,\r
+ IN UINT32 NodeCount,\r
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer\r
+ )\r
+{\r
+ UINT32 Size;\r
+\r
+ ASSERT (NodeList != NULL);\r
+\r
+ Size = 0;\r
+ while (NodeCount-- != 0) {\r
+ (*NodeIndexer)->Token = NodeList->Token;\r
+ (*NodeIndexer)->Object = (VOID*)NodeList;\r
+ (*NodeIndexer)->Offset = Size + NodeStartOffset;\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",\r
+ *NodeIndexer,\r
+ (*NodeIndexer)->Token,\r
+ (*NodeIndexer)->Object,\r
+ (*NodeIndexer)->Offset\r
+ ));\r
+\r
+ Size += GetPmcgNodeSize (NodeList);\r
+ (*NodeIndexer)++;\r
+ NodeList++;\r
+ }\r
+ return Size;\r
+}\r
+\r
+/** Returns the offset of the Node referenced by the Token.\r
+\r
+ @param [in] NodeIndexer Pointer to node indexer array.\r
+ @param [in] NodeCount Count of the nodes.\r
+ @param [in] Token Reference token for the node.\r
+ @param [out] NodeOffset Offset of the node from the\r
+ start of the IORT table.\r
+\r
+ @retval EFI_SUCCESS Success.\r
+ @retval EFI_NOT_FOUND No matching token reference\r
+ found in node indexer array.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+GetNodeOffsetReferencedByToken (\r
+ IN IORT_NODE_INDEXER * NodeIndexer,\r
+ IN UINT32 NodeCount,\r
+ IN CM_OBJECT_TOKEN Token,\r
+ OUT UINT32 * NodeOffset\r
+ )\r
+{\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "IORT: Node Indexer: Search Token = %p\n",\r
+ Token\r
+ ));\r
+ while (NodeCount-- != 0) {\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "IORT: Node Indexer: NodeIndexer->Token = %p, Offset = %d\n",\r
+ NodeIndexer->Token,\r
+ NodeIndexer->Offset\r
+ ));\r
+ if (NodeIndexer->Token == Token) {\r
+ *NodeOffset = NodeIndexer->Offset;\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "IORT: Node Indexer: Token = %p, Found\n",\r
+ Token\r
+ ));\r
+ return EFI_SUCCESS;\r
+ }\r
+ NodeIndexer++;\r
+ }\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "IORT: Node Indexer: Token = %p, Not Found\n",\r
+ Token\r
+ ));\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/** Update the Id Mapping Array.\r
+\r
+ This function retrieves the Id Mapping Array object referenced by the\r
+ IdMappingToken and updates the IdMapArray.\r
+\r
+ @param [in] This Pointer to the table Generator.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [in] IdMapArray Pointer to an array of Id Mappings.\r
+ @param [in] IdCount Number of Id Mappings.\r
+ @param [in] IdMappingToken Reference Token for retrieving the\r
+ Id Mapping Array object.\r
+\r
+ @retval EFI_SUCCESS Table generated successfully.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The required object was not found.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+AddIdMappingArray (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ IN EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray,\r
+ IN UINT32 IdCount,\r
+ IN CONST CM_OBJECT_TOKEN IdMappingToken\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CM_ARM_ID_MAPPING * IdMappings;\r
+ UINT32 IdMappingCount;\r
+ ACPI_IORT_GENERATOR * Generator;\r
+\r
+ ASSERT (IdMapArray != NULL);\r
+\r
+ Generator = (ACPI_IORT_GENERATOR*)This;\r
+\r
+ // Get the Id Mapping Array\r
+ Status = GetEArmObjIdMapping (\r
+ CfgMgrProtocol,\r
+ IdMappingToken,\r
+ &IdMappings,\r
+ &IdMappingCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to get Id Mapping array. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+\r
+ if (IdMappingCount < IdCount) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to get the required number of Id Mappings.\n"\r
+ ));\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ // Populate the Id Mapping array\r
+ while (IdCount-- != 0) {\r
+ Status = GetNodeOffsetReferencedByToken (\r
+ Generator->NodeIndexer,\r
+ Generator->IortNodeCount,\r
+ IdMappings->OutputReferenceToken,\r
+ &IdMapArray->OutputReference\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to get Output Reference for ITS Identifier array."\r
+ "Reference Token = %p"\r
+ " Status = %r\n",\r
+ IdMappings->OutputReferenceToken,\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+\r
+ IdMapArray->InputBase = IdMappings->InputBase;\r
+ IdMapArray->NumIds = IdMappings->NumIds;\r
+ IdMapArray->OutputBase = IdMappings->OutputBase;\r
+ IdMapArray->Flags = IdMappings->Flags;\r
+\r
+ IdMapArray++;\r
+ IdMappings++;\r
+ } // Id Mapping array\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Update the ITS Group Node Information.\r
+\r
+ @param [in] This Pointer to the table Generator.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [in] Iort Pointer to IORT table structure.\r
+ @param [in] NodesStartOffset Offset for the start of the ITS Group\r
+ Nodes.\r
+ @param [in] NodeList Pointer to an array of ITS Group Node\r
+ Objects.\r
+ @param [in] NodeCount Number of ITS Group Node Objects.\r
+\r
+ @retval EFI_SUCCESS Table generated successfully.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The required object was not found.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+AddItsGroupNodes (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort,\r
+ IN CONST UINT32 NodesStartOffset,\r
+ IN CONST CM_ARM_ITS_GROUP_NODE * NodeList,\r
+ IN UINT32 NodeCount\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE * ItsGroupNode;\r
+ UINT32 * ItsIds;\r
+ CM_ARM_ITS_IDENTIFIER * ItsIdentifier;\r
+ UINT32 ItsIdentifierCount;\r
+ UINT32 IdIndex;\r
+\r
+ ASSERT (Iort != NULL);\r
+\r
+ ItsGroupNode = (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE*)((UINT8*)Iort +\r
+ NodesStartOffset);\r
+\r
+ while (NodeCount-- != 0) {\r
+ // Populate the node header\r
+ ItsGroupNode->Node.Type = EFI_ACPI_IORT_TYPE_ITS_GROUP;\r
+ ItsGroupNode->Node.Length = GetItsGroupNodeSize (NodeList);\r
+ ItsGroupNode->Node.Revision = 0;\r
+ ItsGroupNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;\r
+ ItsGroupNode->Node.NumIdMappings = 0;\r
+ ItsGroupNode->Node.IdReference = 0;\r
+\r
+ // IORT specific data\r
+ ItsGroupNode->NumItsIdentifiers = NodeList->ItsIdCount;\r
+ ItsIds = (UINT32*)((UINT8*)ItsGroupNode +\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE));\r
+\r
+ Status = GetEArmObjGicItsIdentifierArray (\r
+ CfgMgrProtocol,\r
+ NodeList->ItsIdToken,\r
+ &ItsIdentifier,\r
+ &ItsIdentifierCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to get ITS Identifier array. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+\r
+ if (ItsIdentifierCount < ItsGroupNode->NumItsIdentifiers) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to get the required number of ITS Identifiers.\n"\r
+ ));\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ // Populate the ITS identifier array\r
+ for (IdIndex = 0; IdIndex < ItsGroupNode->NumItsIdentifiers; IdIndex++) {\r
+ ItsIds[IdIndex] = ItsIdentifier[IdIndex].ItsId;\r
+ } // ITS identifier array\r
+\r
+ // Next IORT Group Node\r
+ ItsGroupNode = (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE*)((UINT8*)ItsGroupNode +\r
+ ItsGroupNode->Node.Length);\r
+ NodeList++;\r
+ } // IORT Group Node\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Update the Named Component Node Information.\r
+\r
+ This function updates the Named Component node information in the IORT\r
+ table.\r
+\r
+ @param [in] This Pointer to the table Generator.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [in] Iort Pointer to IORT table structure.\r
+ @param [in] NodesStartOffset Offset for the start of the Named\r
+ Component Nodes.\r
+ @param [in] NodeList Pointer to an array of Named Component\r
+ Node Objects.\r
+ @param [in] NodeCount Number of Named Component Node Objects.\r
+\r
+ @retval EFI_SUCCESS Table generated successfully.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The required object was not found.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+AddNamedComponentNodes (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort,\r
+ IN CONST UINT32 NodesStartOffset,\r
+ IN CONST CM_ARM_NAMED_COMPONENT_NODE * NodeList,\r
+ IN UINT32 NodeCount\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE * NcNode;\r
+ EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;\r
+ UINT32 ObjectNameLenght;\r
+ CHAR8 * ObjectName;\r
+\r
+ ASSERT (Iort != NULL);\r
+\r
+ NcNode = (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE*)((UINT8*)Iort +\r
+ NodesStartOffset);\r
+\r
+ while (NodeCount-- != 0) {\r
+ // Populate the node header\r
+ NcNode->Node.Type = EFI_ACPI_IORT_TYPE_NAMED_COMP;\r
+ NcNode->Node.Length =\r
+ GetNamedComponentNodeSize (NodeList);\r
+ NcNode->Node.Revision = 2;\r
+ NcNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;\r
+ NcNode->Node.NumIdMappings = NodeList->IdMappingCount;\r
+\r
+ ObjectNameLenght = AsciiStrLen (NodeList->ObjectName) + 1;\r
+ NcNode->Node.IdReference =\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE) +\r
+ (ALIGN_VALUE (ObjectNameLenght, 4));\r
+\r
+ // Named Component specific data\r
+ NcNode->Flags = NodeList->Flags;\r
+ NcNode->CacheCoherent = NodeList->CacheCoherent;\r
+ NcNode->AllocationHints = NodeList->AllocationHints;\r
+ NcNode->Reserved = EFI_ACPI_RESERVED_WORD;\r
+ NcNode->MemoryAccessFlags = NodeList->MemoryAccessFlags;\r
+ NcNode->AddressSizeLimit = NodeList->AddressSizeLimit;\r
+\r
+ // Copy the object name\r
+ ObjectName = (CHAR8*)((UINT8*)NcNode +\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE));\r
+ Status = AsciiStrCpyS (\r
+ ObjectName,\r
+ ObjectNameLenght,\r
+ NodeList->ObjectName\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to copy Object Name. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+\r
+ if ((NodeList->IdMappingCount > 0) &&\r
+ (NodeList->IdMappingToken != CM_NULL_TOKEN)) {\r
+ // Ids for Named Component\r
+ IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)NcNode +\r
+ NcNode->Node.IdReference);\r
+\r
+ Status = AddIdMappingArray (\r
+ This,\r
+ CfgMgrProtocol,\r
+ IdMapArray,\r
+ NodeList->IdMappingCount,\r
+ NodeList->IdMappingToken\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ // Next Named Component Node\r
+ NcNode = (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE*)((UINT8*)NcNode +\r
+ NcNode->Node.Length);\r
+ NodeList++;\r
+ } // Named Component Node\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Update the Root Complex Node Information.\r
+\r
+ This function updates the Root Complex node information in the IORT table.\r
+\r
+ @param [in] This Pointer to the table Generator.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [in] Iort Pointer to IORT table structure.\r
+ @param [in] NodesStartOffset Offset for the start of the Root Complex\r
+ Nodes.\r
+ @param [in] NodeList Pointer to an array of Root Complex Node\r
+ Objects.\r
+ @param [in] NodeCount Number of Root Complex Node Objects.\r
+\r
+ @retval EFI_SUCCESS Table generated successfully.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The required object was not found.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+AddRootComplexNodes (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort,\r
+ IN CONST UINT32 NodesStartOffset,\r
+ IN CONST CM_ARM_ROOT_COMPLEX_NODE * NodeList,\r
+ IN UINT32 NodeCount\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ACPI_6_0_IO_REMAPPING_RC_NODE * RcNode;\r
+ EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;\r
+\r
+ ASSERT (Iort != NULL);\r
+\r
+ RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE*)((UINT8*)Iort +\r
+ NodesStartOffset);\r
+\r
+ while (NodeCount-- != 0) {\r
+ // Populate the node header\r
+ RcNode->Node.Type = EFI_ACPI_IORT_TYPE_ROOT_COMPLEX;\r
+ RcNode->Node.Length = GetRootComplexNodeSize (NodeList);\r
+ RcNode->Node.Revision = 1;\r
+ RcNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;\r
+ RcNode->Node.NumIdMappings = NodeList->IdMappingCount;\r
+ RcNode->Node.IdReference = sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE);\r
+\r
+ // Root Complex specific data\r
+ RcNode->CacheCoherent = NodeList->CacheCoherent;\r
+ RcNode->AllocationHints = NodeList->AllocationHints;\r
+ RcNode->Reserved = EFI_ACPI_RESERVED_WORD;\r
+ RcNode->MemoryAccessFlags = NodeList->MemoryAccessFlags;\r
+ RcNode->AtsAttribute = NodeList->AtsAttribute;\r
+ RcNode->PciSegmentNumber = NodeList->PciSegmentNumber;\r
+ RcNode->MemoryAddressSize = NodeList->MemoryAddressSize;\r
+ RcNode->Reserved1[0] = EFI_ACPI_RESERVED_BYTE;\r
+ RcNode->Reserved1[1] = EFI_ACPI_RESERVED_BYTE;\r
+ RcNode->Reserved1[2] = EFI_ACPI_RESERVED_BYTE;\r
+\r
+ if ((NodeList->IdMappingCount > 0) &&\r
+ (NodeList->IdMappingToken != CM_NULL_TOKEN)) {\r
+ // Ids for Root Complex\r
+ IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)RcNode +\r
+ RcNode->Node.IdReference);\r
+ Status = AddIdMappingArray (\r
+ This,\r
+ CfgMgrProtocol,\r
+ IdMapArray,\r
+ NodeList->IdMappingCount,\r
+ NodeList->IdMappingToken\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ // Next Root Complex Node\r
+ RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE*)((UINT8*)RcNode +\r
+ RcNode->Node.Length);\r
+ NodeList++;\r
+ } // Root Complex Node\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Update the SMMU Interrupt Array.\r
+\r
+ This function retrieves the InterruptArray object referenced by the\r
+ InterruptToken and updates the SMMU InterruptArray.\r
+\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [in, out] InterruptArray Pointer to an array of Interrupts.\r
+ @param [in] InterruptCount Number of entries in the InterruptArray.\r
+ @param [in] InterruptToken Reference Token for retrieving the SMMU\r
+ InterruptArray object.\r
+\r
+ @retval EFI_SUCCESS Table generated successfully.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The required object was not found.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+AddSmmuInterrruptArray (\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ IN OUT EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT * InterruptArray,\r
+ IN UINT32 InterruptCount,\r
+ IN CONST CM_OBJECT_TOKEN InterruptToken\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CM_ARM_SMMU_INTERRUPT * SmmuInterrupt;\r
+ UINT32 SmmuInterruptCount;\r
+\r
+ ASSERT (InterruptArray != NULL);\r
+\r
+ // Get the SMMU Interrupt Array\r
+ Status = GetEArmObjSmmuInterruptArray (\r
+ CfgMgrProtocol,\r
+ InterruptToken,\r
+ &SmmuInterrupt,\r
+ &SmmuInterruptCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to get SMMU Interrupt array. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+\r
+ if (SmmuInterruptCount < InterruptCount) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to get the required number of SMMU Interrupts.\n"\r
+ ));\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ // Populate the Id Mapping array\r
+ while (InterruptCount-- != 0) {\r
+ InterruptArray->Interrupt = SmmuInterrupt->Interrupt;\r
+ InterruptArray->InterruptFlags = SmmuInterrupt->Flags;\r
+ InterruptArray++;\r
+ SmmuInterrupt++;\r
+ } // Id Mapping array\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Update the SMMU v1/v2 Node Information.\r
+\r
+ @param [in] This Pointer to the table Generator.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [in] Iort Pointer to IORT table structure.\r
+ @param [in] NodesStartOffset Offset for the start of the SMMU v1/v2\r
+ Nodes.\r
+ @param [in] NodeList Pointer to an array of SMMU v1/v2 Node\r
+ Objects.\r
+ @param [in] NodeCount Number of SMMU v1/v2 Node Objects.\r
+\r
+ @retval EFI_SUCCESS Table generated successfully.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The required object was not found.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+AddSmmuV1V2Nodes (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort,\r
+ IN CONST UINT32 NodesStartOffset,\r
+ IN CONST CM_ARM_SMMUV1_SMMUV2_NODE * NodeList,\r
+ IN UINT32 NodeCount\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE * SmmuNode;\r
+ EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;\r
+\r
+ EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT * ContextInterruptArray;\r
+ EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT * PmuInterruptArray;\r
+\r
+ ASSERT (Iort != NULL);\r
+\r
+ SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE*)((UINT8*)Iort +\r
+ NodesStartOffset);\r
+\r
+ while (NodeCount-- != 0) {\r
+ // Populate the node header\r
+ SmmuNode->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv1v2;\r
+ SmmuNode->Node.Length = GetSmmuV1V2NodeSize (NodeList);\r
+ SmmuNode->Node.Revision = 0;\r
+ SmmuNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;\r
+ SmmuNode->Node.NumIdMappings = NodeList->IdMappingCount;\r
+ SmmuNode->Node.IdReference = sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE) +\r
+ (NodeList->ContextInterruptCount *\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)) +\r
+ (NodeList->PmuInterruptCount *\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));\r
+\r
+ // SMMU v1/v2 specific data\r
+ SmmuNode->Base = NodeList->BaseAddress;\r
+ SmmuNode->Span = NodeList->Span;\r
+ SmmuNode->Model = NodeList->Model;\r
+ SmmuNode->Flags = NodeList->Flags;\r
+\r
+ // Reference to Global Interrupt Array\r
+ SmmuNode->GlobalInterruptArrayRef =\r
+ OFFSET_OF (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE, SMMU_NSgIrpt);\r
+\r
+ // Context Interrupt\r
+ SmmuNode->NumContextInterrupts = NodeList->ContextInterruptCount;\r
+ SmmuNode->ContextInterruptArrayRef =\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE);\r
+ ContextInterruptArray =\r
+ (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT*)((UINT8*)SmmuNode +\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE));\r
+\r
+ // PMU Interrupt\r
+ SmmuNode->NumPmuInterrupts = NodeList->PmuInterruptCount;\r
+ SmmuNode->PmuInterruptArrayRef = SmmuNode->ContextInterruptArrayRef +\r
+ (NodeList->ContextInterruptCount *\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));\r
+ PmuInterruptArray =\r
+ (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT*)((UINT8*)SmmuNode +\r
+ SmmuNode->PmuInterruptArrayRef);\r
+\r
+ SmmuNode->SMMU_NSgIrpt = NodeList->SMMU_NSgIrpt;\r
+ SmmuNode->SMMU_NSgIrptFlags = NodeList->SMMU_NSgIrptFlags;\r
+ SmmuNode->SMMU_NSgCfgIrpt = NodeList->SMMU_NSgCfgIrpt;\r
+ SmmuNode->SMMU_NSgCfgIrptFlags = NodeList->SMMU_NSgCfgIrptFlags;\r
+\r
+ // Add Context Interrupt Array\r
+ Status = AddSmmuInterrruptArray (\r
+ CfgMgrProtocol,\r
+ ContextInterruptArray,\r
+ SmmuNode->NumContextInterrupts,\r
+ NodeList->ContextInterruptToken\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to Context Interrupt Array. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+\r
+ // Add PMU Interrupt Array\r
+ if ((SmmuNode->NumPmuInterrupts > 0) &&\r
+ (NodeList->PmuInterruptToken != CM_NULL_TOKEN)) {\r
+ Status = AddSmmuInterrruptArray (\r
+ CfgMgrProtocol,\r
+ PmuInterruptArray,\r
+ SmmuNode->NumPmuInterrupts,\r
+ NodeList->PmuInterruptToken\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to PMU Interrupt Array. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ if ((NodeList->IdMappingCount > 0) &&\r
+ (NodeList->IdMappingToken != CM_NULL_TOKEN)) {\r
+ // Ids for SMMU v1/v2 Node\r
+ IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)SmmuNode +\r
+ SmmuNode->Node.IdReference);\r
+ Status = AddIdMappingArray (\r
+ This,\r
+ CfgMgrProtocol,\r
+ IdMapArray,\r
+ NodeList->IdMappingCount,\r
+ NodeList->IdMappingToken\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+ }\r
+ // Next SMMU v1/v2 Node\r
+ SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE*)((UINT8*)SmmuNode +\r
+ SmmuNode->Node.Length);\r
+ NodeList++;\r
+ } // SMMU v1/v2 Node\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Update the SMMUv3 Node Information.\r
+\r
+ This function updates the SMMUv3 node information in the IORT table.\r
+\r
+ @param [in] This Pointer to the table Generator.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [in] Iort Pointer to IORT table structure.\r
+ @param [in] NodesStartOffset Offset for the start of the SMMUv3 Nodes.\r
+ @param [in] NodeList Pointer to an array of SMMUv3 Node Objects.\r
+ @param [in] NodeCount Number of SMMUv3 Node Objects.\r
+\r
+ @retval EFI_SUCCESS Table generated successfully.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The required object was not found.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+AddSmmuV3Nodes (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort,\r
+ IN CONST UINT32 NodesStartOffset,\r
+ IN CONST CM_ARM_SMMUV3_NODE * NodeList,\r
+ IN UINT32 NodeCount\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE * SmmuV3Node;\r
+ EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;\r
+\r
+ ASSERT (Iort != NULL);\r
+\r
+ SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE*)((UINT8*)Iort +\r
+ NodesStartOffset);\r
+\r
+ while (NodeCount-- != 0) {\r
+ // Populate the node header\r
+ SmmuV3Node->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv3;\r
+ SmmuV3Node->Node.Length = GetSmmuV3NodeSize (NodeList);\r
+ SmmuV3Node->Node.Revision = 2;\r
+ SmmuV3Node->Node.Reserved = EFI_ACPI_RESERVED_DWORD;\r
+ SmmuV3Node->Node.NumIdMappings = NodeList->IdMappingCount;\r
+ SmmuV3Node->Node.IdReference =\r
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE);\r
+\r
+ // SMMUv3 specific data\r
+ SmmuV3Node->Base = NodeList->BaseAddress;\r
+ SmmuV3Node->Flags = NodeList->Flags;\r
+ SmmuV3Node->Reserved = EFI_ACPI_RESERVED_WORD;\r
+ SmmuV3Node->VatosAddress = NodeList->VatosAddress;\r
+ SmmuV3Node->Model = NodeList->Model;\r
+ SmmuV3Node->Event = NodeList->EventInterrupt;\r
+ SmmuV3Node->Pri = NodeList->PriInterrupt;\r
+ SmmuV3Node->Gerr = NodeList->GerrInterrupt;\r
+ SmmuV3Node->Sync = NodeList->SyncInterrupt;\r
+\r
+ if ((SmmuV3Node->Flags & EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN) != 0) {\r
+ // The Proximity Domain Valid flag is set to 1\r
+ SmmuV3Node->ProximityDomain = NodeList->ProximityDomain;\r
+ } else {\r
+ SmmuV3Node->ProximityDomain = 0;\r
+ }\r
+\r
+ if ((SmmuV3Node->Event != 0) && (SmmuV3Node->Pri != 0) &&\r
+ (SmmuV3Node->Gerr != 0) && (SmmuV3Node->Sync != 0)) {\r
+ // If all the SMMU control interrupts are GSIV based,\r
+ // the DeviceID mapping index field is ignored.\r
+ SmmuV3Node->DeviceIdMappingIndex = 0;\r
+ } else {\r
+ SmmuV3Node->DeviceIdMappingIndex = NodeList->DeviceIdMappingIndex;\r
+ }\r
+\r
+ if ((NodeList->IdMappingCount > 0) &&\r
+ (NodeList->IdMappingToken != CM_NULL_TOKEN)) {\r
+ // Ids for SMMUv3 node\r
+ IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)SmmuV3Node +\r
+ SmmuV3Node->Node.IdReference);\r
+ Status = AddIdMappingArray (\r
+ This,\r
+ CfgMgrProtocol,\r
+ IdMapArray,\r
+ NodeList->IdMappingCount,\r
+ NodeList->IdMappingToken\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ // Next SMMUv3 Node\r
+ SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE*)((UINT8*)SmmuV3Node +\r
+ SmmuV3Node->Node.Length);\r
+ NodeList++;\r
+ } // SMMUv3 Node\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Update the PMCG Node Information.\r
+\r
+ This function updates the PMCG node information in the IORT table.\r
+\r
+ @param [in] This Pointer to the table Generator.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [in] Iort Pointer to IORT table structure.\r
+ @param [in] NodesStartOffset Offset for the start of the PMCG Nodes.\r
+ @param [in] NodeList Pointer to an array of PMCG Node Objects.\r
+ @param [in] NodeCount Number of PMCG Node Objects.\r
+\r
+ @retval EFI_SUCCESS Table generated successfully.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The required object was not found.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+AddPmcgNodes (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort,\r
+ IN CONST UINT32 NodesStartOffset,\r
+ IN CONST CM_ARM_PMCG_NODE * NodeList,\r
+ IN UINT32 NodeCount\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE * PmcgNode;\r
+ EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;\r
+ ACPI_IORT_GENERATOR * Generator;\r
+\r
+ ASSERT (Iort != NULL);\r
+\r
+ Generator = (ACPI_IORT_GENERATOR*)This;\r
+ PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE*)((UINT8*)Iort +\r
+ NodesStartOffset);\r
+\r
+ while (NodeCount-- != 0) {\r
+ // Populate the node header\r
+ PmcgNode->Node.Type = EFI_ACPI_IORT_TYPE_PMCG;\r
+ PmcgNode->Node.Length = GetPmcgNodeSize (NodeList);\r
+ PmcgNode->Node.Revision = 1;\r
+ PmcgNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;\r
+ PmcgNode->Node.NumIdMappings = NodeList->IdMappingCount;\r
+ PmcgNode->Node.IdReference = sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE);\r
+\r
+ // PMCG specific data\r
+ PmcgNode->Base = NodeList->BaseAddress;\r
+ PmcgNode->OverflowInterruptGsiv = NodeList->OverflowInterrupt;\r
+ PmcgNode->Page1Base = NodeList->Page1BaseAddress;\r
+\r
+ Status = GetNodeOffsetReferencedByToken (\r
+ Generator->NodeIndexer,\r
+ Generator->IortNodeCount,\r
+ NodeList->ReferenceToken,\r
+ &PmcgNode->NodeReference\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to get Output Reference for PMCG Node."\r
+ "Reference Token = %p"\r
+ " Status = %r\n",\r
+ NodeList->ReferenceToken,\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+\r
+ if ((NodeList->IdMappingCount > 0) &&\r
+ (NodeList->IdMappingToken != CM_NULL_TOKEN)) {\r
+ // Ids for PMCG node\r
+ IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)PmcgNode +\r
+ PmcgNode->Node.IdReference);\r
+\r
+ Status = AddIdMappingArray (\r
+ This,\r
+ CfgMgrProtocol,\r
+ IdMapArray,\r
+ NodeList->IdMappingCount,\r
+ NodeList->IdMappingToken\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ // Next PMCG Node\r
+ PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE*)((UINT8*)PmcgNode +\r
+ PmcgNode->Node.Length);\r
+ NodeList++;\r
+ } // PMCG Node\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Construct the IORT ACPI table.\r
+\r
+ This function invokes the Configuration Manager protocol interface\r
+ to get the required hardware information for generating the ACPI\r
+ table.\r
+\r
+ If this function allocates any resources then they must be freed\r
+ in the FreeXXXXTableResources function.\r
+\r
+ @param [in] This Pointer to the table generator.\r
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [out] Table Pointer to the constructed ACPI Table.\r
+\r
+ @retval EFI_SUCCESS Table generated successfully.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The required object was not found.\r
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration\r
+ Manager is less than the Object size for the\r
+ requested object.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+BuildIortTable (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 TableSize;\r
+ UINT32 IortNodeCount;\r
+\r
+ UINT32 ItsGroupNodeCount;\r
+ UINT32 NamedComponentNodeCount;\r
+ UINT32 RootComplexNodeCount;\r
+ UINT32 SmmuV1V2NodeCount;\r
+ UINT32 SmmuV3NodeCount;\r
+ UINT32 PmcgNodeCount;\r
+\r
+ UINT32 ItsGroupOffset;\r
+ UINT32 NamedComponentOffset;\r
+ UINT32 RootComplexOffset;\r
+ UINT32 SmmuV1V2Offset;\r
+ UINT32 SmmuV3Offset;\r
+ UINT32 PmcgOffset;\r
+\r
+ CM_ARM_ITS_GROUP_NODE * ItsGroupNodeList;\r
+ CM_ARM_NAMED_COMPONENT_NODE * NamedComponentNodeList;\r
+ CM_ARM_ROOT_COMPLEX_NODE * RootComplexNodeList;\r
+ CM_ARM_SMMUV1_SMMUV2_NODE * SmmuV1V2NodeList;\r
+ CM_ARM_SMMUV3_NODE * SmmuV3NodeList;\r
+ CM_ARM_PMCG_NODE * PmcgNodeList;\r
+\r
+ EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort;\r
+ IORT_NODE_INDEXER * NodeIndexer;\r
+ ACPI_IORT_GENERATOR * Generator;\r
+\r
+ ASSERT (This != NULL);\r
+ ASSERT (AcpiTableInfo != NULL);\r
+ ASSERT (CfgMgrProtocol != NULL);\r
+ ASSERT (Table != NULL);\r
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
+\r
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||\r
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Requested table revision = %d, is not supported."\r
+ "Supported table revision: Minimum = %d, Maximum = %d\n",\r
+ AcpiTableInfo->AcpiTableRevision,\r
+ This->MinAcpiTableRevision,\r
+ This->AcpiTableRevision\r
+ ));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Generator = (ACPI_IORT_GENERATOR*)This;\r
+ *Table = NULL;\r
+\r
+ // Get the ITS group node info\r
+ Status = GetEArmObjItsGroup (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ &ItsGroupNodeList,\r
+ &ItsGroupNodeCount\r
+ );\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to get ITS Group Node Info. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ // Add the ITS group node count\r
+ IortNodeCount = ItsGroupNodeCount;\r
+\r
+ // Get the Named component node info\r
+ Status = GetEArmObjNamedComponent (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ &NamedComponentNodeList,\r
+ &NamedComponentNodeCount\r
+ );\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to get Named Component Node Info. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ // Add the Named Component group count\r
+ IortNodeCount += NamedComponentNodeCount;\r
+\r
+ // Get the Root complex node info\r
+ Status = GetEArmObjRootComplex (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ &RootComplexNodeList,\r
+ &RootComplexNodeCount\r
+ );\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to get Root Complex Node Info. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ // Add the Root Complex node count\r
+ IortNodeCount += RootComplexNodeCount;\r
+\r
+ // Get the SMMU v1/v2 node info\r
+ Status = GetEArmObjSmmuV1SmmuV2 (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ &SmmuV1V2NodeList,\r
+ &SmmuV1V2NodeCount\r
+ );\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to get SMMUv1/SMMUv2 Node Info. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ // Add the SMMU v1/v2 node count\r
+ IortNodeCount += SmmuV1V2NodeCount;\r
+\r
+ // Get the SMMUv3 node info\r
+ Status = GetEArmObjSmmuV3 (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ &SmmuV3NodeList,\r
+ &SmmuV3NodeCount\r
+ );\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to get SMMUv3 Node Info. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ // Add the SMMUv3 node count\r
+ IortNodeCount += SmmuV3NodeCount;\r
+\r
+ // Get the PMCG node info\r
+ Status = GetEArmObjPmcg (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ &PmcgNodeList,\r
+ &PmcgNodeCount\r
+ );\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to get PMCG Node Info. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ // Add the PMCG node count\r
+ IortNodeCount += PmcgNodeCount;\r
+\r
+ // Allocate Node Indexer array\r
+ NodeIndexer = (IORT_NODE_INDEXER*)AllocateZeroPool (\r
+ (sizeof (IORT_NODE_INDEXER) *\r
+ IortNodeCount)\r
+ );\r
+ if (NodeIndexer == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to allocate memory for Node Indexer" \\r
+ " Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "INFO: NodeIndexer = %p\n", NodeIndexer));\r
+ Generator->IortNodeCount = IortNodeCount;\r
+ Generator->NodeIndexer = NodeIndexer;\r
+\r
+ // Calculate the size of the IORT table\r
+ TableSize = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);\r
+\r
+ // ITS Group Nodes\r
+ if (ItsGroupNodeCount > 0) {\r
+ ItsGroupOffset = TableSize;\r
+ // Size of ITS Group node list.\r
+ TableSize += GetSizeofItsGroupNodes (\r
+ ItsGroupOffset,\r
+ ItsGroupNodeList,\r
+ ItsGroupNodeCount,\r
+ &NodeIndexer\r
+ );\r
+ }\r
+\r
+ // Named Component Nodes\r
+ if (NamedComponentNodeCount > 0) {\r
+ NamedComponentOffset = TableSize;\r
+ // Size of Named Component node list.\r
+ TableSize += GetSizeofNamedComponentNodes (\r
+ NamedComponentOffset,\r
+ NamedComponentNodeList,\r
+ NamedComponentNodeCount,\r
+ &NodeIndexer\r
+ );\r
+ }\r
+\r
+ // Root Complex Nodes\r
+ if (RootComplexNodeCount > 0) {\r
+ RootComplexOffset = TableSize;\r
+ // Size of Root Complex node list.\r
+ TableSize += GetSizeofRootComplexNodes (\r
+ RootComplexOffset,\r
+ RootComplexNodeList,\r
+ RootComplexNodeCount,\r
+ &NodeIndexer\r
+ );\r
+ }\r
+\r
+ // SMMUv1/SMMUv2 Nodes\r
+ if (SmmuV1V2NodeCount > 0) {\r
+ SmmuV1V2Offset = TableSize;\r
+ // Size of SMMUv1/SMMUv2 node list.\r
+ TableSize += GetSizeofSmmuV1V2Nodes (\r
+ SmmuV1V2Offset,\r
+ SmmuV1V2NodeList,\r
+ SmmuV1V2NodeCount,\r
+ &NodeIndexer\r
+ );\r
+ }\r
+\r
+ // SMMUv3 Nodes\r
+ if (SmmuV3NodeCount > 0) {\r
+ SmmuV3Offset = TableSize;\r
+ // Size of SMMUv3 node list.\r
+ TableSize += GetSizeofSmmuV3Nodes (\r
+ SmmuV3Offset,\r
+ SmmuV3NodeList,\r
+ SmmuV3NodeCount,\r
+ &NodeIndexer\r
+ );\r
+ }\r
+\r
+ // PMCG Nodes\r
+ if (PmcgNodeCount > 0) {\r
+ PmcgOffset = TableSize;\r
+ // Size of PMCG node list.\r
+ TableSize += GetSizeofPmcgNodes (\r
+ PmcgOffset,\r
+ PmcgNodeList,\r
+ PmcgNodeCount,\r
+ &NodeIndexer\r
+ );\r
+ }\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "INFO: IORT:\n" \\r
+ " IortNodeCount = %d\n" \\r
+ " TableSize = %d\n",\r
+ IortNodeCount,\r
+ TableSize\r
+ ));\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " ItsGroupNodeCount = %d\n" \\r
+ " ItsGroupOffset = %d\n",\r
+ ItsGroupNodeCount,\r
+ ItsGroupOffset\r
+ ));\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " NamedComponentNodeCount = %d\n" \\r
+ " NamedComponentOffset = %d\n",\r
+ NamedComponentNodeCount,\r
+ NamedComponentOffset\r
+ ));\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " RootComplexNodeCount = %d\n" \\r
+ " RootComplexOffset = %d\n",\r
+ RootComplexNodeCount,\r
+ RootComplexOffset\r
+ ));\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " SmmuV1V2NodeCount = %d\n" \\r
+ " SmmuV1V2Offset = %d\n",\r
+ SmmuV1V2NodeCount,\r
+ SmmuV1V2Offset\r
+ ));\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " SmmuV3NodeCount = %d\n" \\r
+ " SmmuV3Offset = %d\n",\r
+ SmmuV3NodeCount,\r
+ SmmuV3Offset\r
+ ));\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ " PmcgNodeCount = %d\n" \\r
+ " PmcgOffset = %d\n",\r
+ PmcgNodeCount,\r
+ PmcgOffset\r
+ ));\r
+\r
+ // Allocate the Buffer for IORT table\r
+ *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);\r
+ if (*Table == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to allocate memory for IORT Table, Size = %d," \\r
+ " Status = %r\n",\r
+ TableSize,\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ Iort = (EFI_ACPI_6_0_IO_REMAPPING_TABLE*)*Table;\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "IORT: Iort = 0x%p TableSize = 0x%x\n",\r
+ Iort,\r
+ TableSize\r
+ ));\r
+\r
+ Status = AddAcpiHeader (\r
+ CfgMgrProtocol,\r
+ This,\r
+ &Iort->Header,\r
+ AcpiTableInfo->AcpiTableRevision,\r
+ TableSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to add ACPI header. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ // Update IORT table\r
+ Iort->NumNodes = IortNodeCount;\r
+ Iort->NodeOffset = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);\r
+ Iort->Reserved = EFI_ACPI_RESERVED_DWORD;\r
+\r
+ if (ItsGroupNodeCount > 0) {\r
+ Status = AddItsGroupNodes (\r
+ This,\r
+ CfgMgrProtocol,\r
+ Iort,\r
+ ItsGroupOffset,\r
+ ItsGroupNodeList,\r
+ ItsGroupNodeCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to add ITS Group Node. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+ }\r
+\r
+ if (NamedComponentNodeCount > 0) {\r
+ Status = AddNamedComponentNodes (\r
+ This,\r
+ CfgMgrProtocol,\r
+ Iort,\r
+ NamedComponentOffset,\r
+ NamedComponentNodeList,\r
+ NamedComponentNodeCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to add Named Component Node. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+ }\r
+\r
+ if (RootComplexNodeCount > 0) {\r
+ Status = AddRootComplexNodes (\r
+ This,\r
+ CfgMgrProtocol,\r
+ Iort,\r
+ RootComplexOffset,\r
+ RootComplexNodeList,\r
+ RootComplexNodeCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to add Root Complex Node. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+ }\r
+\r
+ if (SmmuV1V2NodeCount > 0) {\r
+ Status = AddSmmuV1V2Nodes (\r
+ This,\r
+ CfgMgrProtocol,\r
+ Iort,\r
+ SmmuV1V2Offset,\r
+ SmmuV1V2NodeList,\r
+ SmmuV1V2NodeCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to add SMMU v1/v2 Node. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+ }\r
+\r
+ if (SmmuV3NodeCount > 0) {\r
+ Status = AddSmmuV3Nodes (\r
+ This,\r
+ CfgMgrProtocol,\r
+ Iort,\r
+ SmmuV3Offset,\r
+ SmmuV3NodeList,\r
+ SmmuV3NodeCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+ }\r
+\r
+ if (PmcgNodeCount > 0) {\r
+ Status = AddPmcgNodes (\r
+ This,\r
+ CfgMgrProtocol,\r
+ Iort,\r
+ PmcgOffset,\r
+ PmcgNodeList,\r
+ PmcgNodeCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+error_handler:\r
+ if (Generator->NodeIndexer != NULL) {\r
+ FreePool (Generator->NodeIndexer);\r
+ Generator->NodeIndexer = NULL;\r
+ }\r
+\r
+ if (*Table != NULL) {\r
+ FreePool (*Table);\r
+ *Table = NULL;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/** Free any resources allocated for constructing the IORT\r
+\r
+ @param [in] This Pointer to the table generator.\r
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [in, out] Table Pointer to the ACPI Table.\r
+\r
+ @retval EFI_SUCCESS The resources were freed successfully.\r
+ @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+FreeIortTableResources (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table\r
+ )\r
+{\r
+ ACPI_IORT_GENERATOR * Generator;\r
+ ASSERT (This != NULL);\r
+ ASSERT (AcpiTableInfo != NULL);\r
+ ASSERT (CfgMgrProtocol != NULL);\r
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
+\r
+ Generator = (ACPI_IORT_GENERATOR*)This;\r
+\r
+ // Free any memory allocated by the generator\r
+ if (Generator->NodeIndexer != NULL) {\r
+ FreePool (Generator->NodeIndexer);\r
+ Generator->NodeIndexer = NULL;\r
+ }\r
+\r
+ if ((Table == NULL) || (*Table == NULL)) {\r
+ DEBUG ((DEBUG_ERROR, "ERROR: IORT: Invalid Table Pointer\n"));\r
+ ASSERT ((Table != NULL) && (*Table != NULL));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ FreePool (*Table);\r
+ *Table = NULL;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** The IORT Table Generator revision.\r
+*/\r
+#define IORT_GENERATOR_REVISION CREATE_REVISION (1, 0)\r
+\r
+/** The interface for the MADT Table Generator.\r
+*/\r
+STATIC\r
+ACPI_IORT_GENERATOR IortGenerator = {\r
+ // ACPI table generator header\r
+ {\r
+ // Generator ID\r
+ CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdIort),\r
+ // Generator Description\r
+ L"ACPI.STD.IORT.GENERATOR",\r
+ // ACPI Table Signature\r
+ EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE,\r
+ // ACPI Table Revision supported by this Generator\r
+ EFI_ACPI_IO_REMAPPING_TABLE_REVISION,\r
+ // Minimum supported ACPI Table Revision\r
+ EFI_ACPI_IO_REMAPPING_TABLE_REVISION,\r
+ // Creator ID\r
+ TABLE_GENERATOR_CREATOR_ID_ARM,\r
+ // Creator Revision\r
+ IORT_GENERATOR_REVISION,\r
+ // Build Table function\r
+ BuildIortTable,\r
+ // Free Resource function\r
+ FreeIortTableResources,\r
+ // Extended build function not needed\r
+ NULL,\r
+ // Extended build function not implemented by the generator.\r
+ // Hence extended free resource function is not required.\r
+ NULL\r
+ },\r
+\r
+ // IORT Generator private data\r
+\r
+ // Iort Node count\r
+ 0,\r
+ // Pointer to Iort node indexer\r
+ NULL\r
+};\r
+\r
+/** Register the Generator with the ACPI Table Factory.\r
+\r
+ @param [in] ImageHandle The handle to the image.\r
+ @param [in] SystemTable Pointer to the System Table.\r
+\r
+ @retval EFI_SUCCESS The Generator is registered.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_ALREADY_STARTED The Generator for the Table ID\r
+ is already registered.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AcpiIortLibConstructor (\r
+ IN CONST EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE * CONST SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ Status = RegisterAcpiTableGenerator (&IortGenerator.Header);\r
+ DEBUG ((DEBUG_INFO, "IORT: Register Generator. Status = %r\n", Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+}\r
+\r
+/** Deregister the Generator from the ACPI Table Factory.\r
+\r
+ @param [in] ImageHandle The handle to the image.\r
+ @param [in] SystemTable Pointer to the System Table.\r
+\r
+ @retval EFI_SUCCESS The Generator is deregistered.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The Generator is not registered.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AcpiIortLibDestructor (\r
+ IN CONST EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE * CONST SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ Status = DeregisterAcpiTableGenerator (&IortGenerator.Header);\r
+ DEBUG ((DEBUG_INFO, "Iort: Deregister Generator. Status = %r\n", Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+}\r