| /** @file | |
| IORT Table Generator | |
| Copyright (c) 2017 - 2022, Arm Limited. All rights reserved. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| @par Reference(s): | |
| - IO Remapping Table, Platform Design Document, Revision E.d, Feb 2022 | |
| (https://developer.arm.com/documentation/den0049/) | |
| **/ | |
| #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 | |
| - EArmObjRmr | |
| - EArmObjGicItsIdentifierArray | |
| - EArmObjIdMappingArray | |
| - EArmObjSmmuInterruptArray | |
| - EArmObjMemoryRangeDescriptor | |
| */ | |
| /** 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 | |
| RMR node information from the Configuration Manager. | |
| */ | |
| GET_OBJECT_LIST ( | |
| EObjNameSpaceArm, | |
| EArmObjRmr, | |
| CM_ARM_RMR_NODE | |
| ); | |
| /** This macro expands to a function that retrieves the | |
| Memory Range Descriptor Array information from the Configuration Manager. | |
| */ | |
| GET_OBJECT_LIST ( | |
| EObjNameSpaceArm, | |
| EArmObjMemoryRangeDescriptor, | |
| CM_ARM_MEMORY_RANGE_DESCRIPTOR | |
| ); | |
| /** 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, | |
| EArmObjIdMappingArray, | |
| 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 (UINT32)(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 | |
| UINT64 | |
| GetSizeofItsGroupNodes ( | |
| IN CONST UINT32 NodeStartOffset, | |
| IN CONST CM_ARM_ITS_GROUP_NODE *NodeList, | |
| IN UINT32 NodeCount, | |
| IN OUT IORT_NODE_INDEXER **CONST NodeIndexer | |
| ) | |
| { | |
| UINT64 Size; | |
| ASSERT (NodeList != NULL); | |
| Size = 0; | |
| while (NodeCount-- != 0) { | |
| (*NodeIndexer)->Token = NodeList->Token; | |
| (*NodeIndexer)->Object = (VOID *)NodeList; | |
| (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset); | |
| (*NodeIndexer)->Identifier = NodeList->Identifier; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "IORT: Node Indexer = %p, Token = %p, Object = %p," | |
| " Offset = 0x%x, Identifier = 0x%x\n", | |
| *NodeIndexer, | |
| (*NodeIndexer)->Token, | |
| (*NodeIndexer)->Object, | |
| (*NodeIndexer)->Offset, | |
| (*NodeIndexer)->Identifier | |
| )); | |
| 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 (UINT32)(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 | |
| UINT64 | |
| GetSizeofNamedComponentNodes ( | |
| IN CONST UINT32 NodeStartOffset, | |
| IN CONST CM_ARM_NAMED_COMPONENT_NODE *NodeList, | |
| IN UINT32 NodeCount, | |
| IN OUT IORT_NODE_INDEXER **CONST NodeIndexer | |
| ) | |
| { | |
| UINT64 Size; | |
| ASSERT (NodeList != NULL); | |
| Size = 0; | |
| while (NodeCount-- != 0) { | |
| (*NodeIndexer)->Token = NodeList->Token; | |
| (*NodeIndexer)->Object = (VOID *)NodeList; | |
| (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset); | |
| (*NodeIndexer)->Identifier = NodeList->Identifier; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "IORT: Node Indexer = %p, Token = %p, Object = %p," | |
| " Offset = 0x%x, Identifier = 0x%x\n", | |
| *NodeIndexer, | |
| (*NodeIndexer)->Token, | |
| (*NodeIndexer)->Object, | |
| (*NodeIndexer)->Offset, | |
| (*NodeIndexer)->Identifier | |
| )); | |
| 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 (UINT32)(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 | |
| UINT64 | |
| GetSizeofRootComplexNodes ( | |
| IN CONST UINT32 NodeStartOffset, | |
| IN CONST CM_ARM_ROOT_COMPLEX_NODE *NodeList, | |
| IN UINT32 NodeCount, | |
| IN OUT IORT_NODE_INDEXER **CONST NodeIndexer | |
| ) | |
| { | |
| UINT64 Size; | |
| ASSERT (NodeList != NULL); | |
| Size = 0; | |
| while (NodeCount-- != 0) { | |
| (*NodeIndexer)->Token = NodeList->Token; | |
| (*NodeIndexer)->Object = (VOID *)NodeList; | |
| (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset); | |
| (*NodeIndexer)->Identifier = NodeList->Identifier; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "IORT: Node Indexer = %p, Token = %p, Object = %p," | |
| " Offset = 0x%x, Identifier = 0x%x\n", | |
| *NodeIndexer, | |
| (*NodeIndexer)->Token, | |
| (*NodeIndexer)->Object, | |
| (*NodeIndexer)->Offset, | |
| (*NodeIndexer)->Identifier | |
| )); | |
| 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 (UINT32)(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 | |
| UINT64 | |
| GetSizeofSmmuV1V2Nodes ( | |
| IN CONST UINT32 NodeStartOffset, | |
| IN CONST CM_ARM_SMMUV1_SMMUV2_NODE *NodeList, | |
| IN UINT32 NodeCount, | |
| IN OUT IORT_NODE_INDEXER **CONST NodeIndexer | |
| ) | |
| { | |
| UINT64 Size; | |
| ASSERT (NodeList != NULL); | |
| Size = 0; | |
| while (NodeCount-- != 0) { | |
| (*NodeIndexer)->Token = NodeList->Token; | |
| (*NodeIndexer)->Object = (VOID *)NodeList; | |
| (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset); | |
| (*NodeIndexer)->Identifier = NodeList->Identifier; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "IORT: Node Indexer = %p, Token = %p, Object = %p," | |
| " Offset = 0x%x, Identifier = 0x%x\n", | |
| *NodeIndexer, | |
| (*NodeIndexer)->Token, | |
| (*NodeIndexer)->Object, | |
| (*NodeIndexer)->Offset, | |
| (*NodeIndexer)->Identifier | |
| )); | |
| 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 (UINT32)(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 | |
| UINT64 | |
| GetSizeofSmmuV3Nodes ( | |
| IN CONST UINT32 NodeStartOffset, | |
| IN CONST CM_ARM_SMMUV3_NODE *NodeList, | |
| IN UINT32 NodeCount, | |
| IN OUT IORT_NODE_INDEXER **CONST NodeIndexer | |
| ) | |
| { | |
| UINT64 Size; | |
| ASSERT (NodeList != NULL); | |
| Size = 0; | |
| while (NodeCount-- != 0) { | |
| (*NodeIndexer)->Token = NodeList->Token; | |
| (*NodeIndexer)->Object = (VOID *)NodeList; | |
| (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset); | |
| (*NodeIndexer)->Identifier = NodeList->Identifier; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "IORT: Node Indexer = %p, Token = %p, Object = %p," | |
| " Offset = 0x%x, Identifier = 0x%x\n", | |
| *NodeIndexer, | |
| (*NodeIndexer)->Token, | |
| (*NodeIndexer)->Object, | |
| (*NodeIndexer)->Offset, | |
| (*NodeIndexer)->Identifier | |
| )); | |
| 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 (UINT32)(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 | |
| UINT64 | |
| GetSizeofPmcgNodes ( | |
| IN CONST UINT32 NodeStartOffset, | |
| IN CONST CM_ARM_PMCG_NODE *NodeList, | |
| IN UINT32 NodeCount, | |
| IN OUT IORT_NODE_INDEXER **CONST NodeIndexer | |
| ) | |
| { | |
| UINT64 Size; | |
| ASSERT (NodeList != NULL); | |
| Size = 0; | |
| while (NodeCount-- != 0) { | |
| (*NodeIndexer)->Token = NodeList->Token; | |
| (*NodeIndexer)->Object = (VOID *)NodeList; | |
| (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset); | |
| (*NodeIndexer)->Identifier = NodeList->Identifier; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "IORT: Node Indexer = %p, Token = %p, Object = %p," | |
| " Offset = 0x%x, Identifier = 0x%x\n", | |
| *NodeIndexer, | |
| (*NodeIndexer)->Token, | |
| (*NodeIndexer)->Object, | |
| (*NodeIndexer)->Offset, | |
| (*NodeIndexer)->Identifier | |
| )); | |
| Size += GetPmcgNodeSize (NodeList); | |
| (*NodeIndexer)++; | |
| NodeList++; | |
| } | |
| return Size; | |
| } | |
| /** Returns the size of the RMR node. | |
| @param [in] Node Pointer to RMR node. | |
| @retval Size of the RMR node. | |
| **/ | |
| STATIC | |
| UINT32 | |
| GetRmrNodeSize ( | |
| IN CONST CM_ARM_RMR_NODE *Node | |
| ) | |
| { | |
| ASSERT (Node != NULL); | |
| /* Size of RMR node + | |
| Size of ID mapping array + | |
| Size of Memory Range Descriptor array | |
| */ | |
| return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE) + | |
| (Node->IdMappingCount * | |
| sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) + | |
| (Node->MemRangeDescCount * | |
| sizeof (EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC))); | |
| } | |
| /** Returns the total size required for the RMR 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 RMR node list. | |
| @param [in] NodeCount Count of the RMR nodes. | |
| @param [in, out] NodeIndexer Pointer to the next Node Indexer. | |
| @retval Total size of the RMR nodes. | |
| **/ | |
| STATIC | |
| UINT64 | |
| GetSizeofRmrNodes ( | |
| IN CONST UINT32 NodeStartOffset, | |
| IN CONST CM_ARM_RMR_NODE *NodeList, | |
| IN UINT32 NodeCount, | |
| IN OUT IORT_NODE_INDEXER **CONST NodeIndexer | |
| ) | |
| { | |
| UINT64 Size; | |
| ASSERT (NodeList != NULL); | |
| Size = 0; | |
| while (NodeCount-- != 0) { | |
| (*NodeIndexer)->Token = NodeList->Token; | |
| (*NodeIndexer)->Object = (VOID *)NodeList; | |
| (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset); | |
| (*NodeIndexer)->Identifier = NodeList->Identifier; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "IORT: Node Indexer = %p, Token = %p, Object = %p," | |
| " Offset = 0x%x, Identifier = 0x%x\n", | |
| *NodeIndexer, | |
| (*NodeIndexer)->Token, | |
| (*NodeIndexer)->Object, | |
| (*NodeIndexer)->Offset, | |
| (*NodeIndexer)->Identifier | |
| )); | |
| Size += GetRmrNodeSize (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 = GetEArmObjIdMappingArray ( | |
| 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] AcpiTableInfo Pointer to the ACPI table info structure. | |
| @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 CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo, | |
| 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; | |
| UINT64 NodeLength; | |
| ASSERT (Iort != NULL); | |
| ItsGroupNode = (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE *)((UINT8 *)Iort + | |
| NodesStartOffset); | |
| while (NodeCount-- != 0) { | |
| NodeLength = GetItsGroupNodeSize (NodeList); | |
| if (NodeLength > MAX_UINT16) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: ITS Id Array Node length 0x%lx > MAX_UINT16." | |
| " Status = %r\n", | |
| NodeLength, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // Populate the node header | |
| ItsGroupNode->Node.Type = EFI_ACPI_IORT_TYPE_ITS_GROUP; | |
| ItsGroupNode->Node.Length = (UINT16)NodeLength; | |
| ItsGroupNode->Node.NumIdMappings = 0; | |
| ItsGroupNode->Node.IdReference = 0; | |
| if (AcpiTableInfo->AcpiTableRevision < | |
| EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05) | |
| { | |
| ItsGroupNode->Node.Revision = 0; | |
| ItsGroupNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD; | |
| } else { | |
| ItsGroupNode->Node.Revision = 1; | |
| ItsGroupNode->Node.Identifier = NodeList->Identifier; | |
| } | |
| // 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] AcpiTableInfo Pointer to the ACPI table info structure. | |
| @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 CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo, | |
| 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; | |
| CHAR8 *ObjectName; | |
| UINTN ObjectNameLength; | |
| UINT64 NodeLength; | |
| ASSERT (Iort != NULL); | |
| NcNode = (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE *)((UINT8 *)Iort + | |
| NodesStartOffset); | |
| while (NodeCount-- != 0) { | |
| NodeLength = GetNamedComponentNodeSize (NodeList); | |
| if (NodeLength > MAX_UINT16) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Named Component Node length 0x%lx > MAX_UINT16." | |
| " Status = %r\n", | |
| NodeLength, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // Populate the node header | |
| NcNode->Node.Type = EFI_ACPI_IORT_TYPE_NAMED_COMP; | |
| NcNode->Node.Length = (UINT16)NodeLength; | |
| NcNode->Node.NumIdMappings = NodeList->IdMappingCount; | |
| if (AcpiTableInfo->AcpiTableRevision < | |
| EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05) | |
| { | |
| NcNode->Node.Revision = 2; | |
| NcNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD; | |
| } else { | |
| NcNode->Node.Revision = 4; | |
| NcNode->Node.Identifier = NodeList->Identifier; | |
| } | |
| ObjectNameLength = AsciiStrLen (NodeList->ObjectName) + 1; | |
| NcNode->Node.IdReference = (NodeList->IdMappingCount == 0) ? | |
| 0 : ((UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE) + | |
| (ALIGN_VALUE (ObjectNameLength, 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, | |
| ObjectNameLength, | |
| 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) { | |
| if (NodeList->IdMappingToken == CM_NULL_TOKEN) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Id Mapping token," | |
| " Token = 0x%x, Status =%r\n", | |
| NodeList->IdMappingToken, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // 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] AcpiTableInfo Pointer to the ACPI table info structure. | |
| @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 CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo, | |
| 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; | |
| UINT64 NodeLength; | |
| ASSERT (Iort != NULL); | |
| RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE *)((UINT8 *)Iort + | |
| NodesStartOffset); | |
| while (NodeCount-- != 0) { | |
| NodeLength = GetRootComplexNodeSize (NodeList); | |
| if (NodeLength > MAX_UINT16) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Root Complex Node length 0x%lx > MAX_UINT16." | |
| " Status = %r\n", | |
| NodeLength, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // Populate the node header | |
| RcNode->Node.Type = EFI_ACPI_IORT_TYPE_ROOT_COMPLEX; | |
| RcNode->Node.Length = (UINT16)NodeLength; | |
| RcNode->Node.NumIdMappings = NodeList->IdMappingCount; | |
| RcNode->Node.IdReference = (NodeList->IdMappingCount == 0) ? | |
| 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE); | |
| if (AcpiTableInfo->AcpiTableRevision < | |
| EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05) | |
| { | |
| RcNode->Node.Revision = 1; | |
| RcNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD; | |
| RcNode->PasidCapabilities = EFI_ACPI_RESERVED_WORD; | |
| } else { | |
| RcNode->Node.Revision = 4; | |
| RcNode->Node.Identifier = NodeList->Identifier; | |
| RcNode->PasidCapabilities = NodeList->PasidCapabilities; | |
| RcNode->Flags = NodeList->Flags; | |
| } | |
| // 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; | |
| if (NodeList->IdMappingCount > 0) { | |
| if (NodeList->IdMappingToken == CM_NULL_TOKEN) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Id Mapping token," | |
| " Token = 0x%x, Status =%r\n", | |
| NodeList->IdMappingToken, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // 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 | |
| AddSmmuInterruptArray ( | |
| 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] AcpiTableInfo Pointer to the ACPI table info structure. | |
| @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 CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo, | |
| 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; | |
| UINT64 NodeLength; | |
| UINT32 Offset; | |
| ASSERT (Iort != NULL); | |
| SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE *)((UINT8 *)Iort + | |
| NodesStartOffset); | |
| while (NodeCount-- != 0) { | |
| NodeLength = GetSmmuV1V2NodeSize (NodeList); | |
| if (NodeLength > MAX_UINT16) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: SMMU V1/V2 Node length 0x%lx > MAX_UINT16. Status = %r\n", | |
| NodeLength, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // Populate the node header | |
| SmmuNode->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv1v2; | |
| SmmuNode->Node.Length = (UINT16)NodeLength; | |
| SmmuNode->Node.NumIdMappings = NodeList->IdMappingCount; | |
| SmmuNode->Node.IdReference = (NodeList->IdMappingCount == 0) ? | |
| 0 : (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))); | |
| if (AcpiTableInfo->AcpiTableRevision < | |
| EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05) | |
| { | |
| SmmuNode->Node.Revision = 1; | |
| SmmuNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD; | |
| } else { | |
| SmmuNode->Node.Revision = 3; | |
| SmmuNode->Node.Identifier = NodeList->Identifier; | |
| } | |
| // 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); | |
| Offset = sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE); | |
| // Context Interrupt | |
| SmmuNode->NumContextInterrupts = NodeList->ContextInterruptCount; | |
| if (NodeList->ContextInterruptCount != 0) { | |
| SmmuNode->ContextInterruptArrayRef = Offset; | |
| ContextInterruptArray = | |
| (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *)((UINT8 *)SmmuNode + Offset); | |
| Offset += (NodeList->ContextInterruptCount * | |
| sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)); | |
| } | |
| // PMU Interrupt | |
| SmmuNode->NumPmuInterrupts = NodeList->PmuInterruptCount; | |
| if (NodeList->PmuInterruptCount != 0) { | |
| SmmuNode->PmuInterruptArrayRef = Offset; | |
| PmuInterruptArray = | |
| (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *)((UINT8 *)SmmuNode + Offset); | |
| } | |
| SmmuNode->SMMU_NSgIrpt = NodeList->SMMU_NSgIrpt; | |
| SmmuNode->SMMU_NSgIrptFlags = NodeList->SMMU_NSgIrptFlags; | |
| SmmuNode->SMMU_NSgCfgIrpt = NodeList->SMMU_NSgCfgIrpt; | |
| SmmuNode->SMMU_NSgCfgIrptFlags = NodeList->SMMU_NSgCfgIrptFlags; | |
| if (NodeList->ContextInterruptCount != 0) { | |
| if (NodeList->ContextInterruptToken == CM_NULL_TOKEN) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Context Interrupt token," | |
| " Token = 0x%x, Status =%r\n", | |
| NodeList->ContextInterruptToken, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // Add Context Interrupt Array | |
| Status = AddSmmuInterruptArray ( | |
| 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) { | |
| if (NodeList->PmuInterruptToken == CM_NULL_TOKEN) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid PMU Interrupt token," | |
| " Token = 0x%x, Status =%r\n", | |
| NodeList->PmuInterruptToken, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| Status = AddSmmuInterruptArray ( | |
| 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) { | |
| if (NodeList->IdMappingToken == CM_NULL_TOKEN) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Id Mapping token," | |
| " Token = 0x%x, Status =%r\n", | |
| NodeList->IdMappingToken, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // 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] AcpiTableInfo Pointer to the ACPI table info structure. | |
| @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 CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo, | |
| 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; | |
| UINT64 NodeLength; | |
| ASSERT (Iort != NULL); | |
| SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *)((UINT8 *)Iort + | |
| NodesStartOffset); | |
| while (NodeCount-- != 0) { | |
| NodeLength = GetSmmuV3NodeSize (NodeList); | |
| if (NodeLength > MAX_UINT16) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: SMMU V3 Node length 0x%lx > MAX_UINT16. Status = %r\n", | |
| NodeLength, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // Populate the node header | |
| SmmuV3Node->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv3; | |
| SmmuV3Node->Node.Length = (UINT16)NodeLength; | |
| SmmuV3Node->Node.NumIdMappings = NodeList->IdMappingCount; | |
| SmmuV3Node->Node.IdReference = (NodeList->IdMappingCount == 0) ? | |
| 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE); | |
| if (AcpiTableInfo->AcpiTableRevision < | |
| EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05) | |
| { | |
| SmmuV3Node->Node.Revision = 2; | |
| SmmuV3Node->Node.Identifier = EFI_ACPI_RESERVED_DWORD; | |
| } else { | |
| SmmuV3Node->Node.Revision = 4; | |
| SmmuV3Node->Node.Identifier = NodeList->Identifier; | |
| } | |
| // 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) { | |
| if (NodeList->IdMappingToken == CM_NULL_TOKEN) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Id Mapping token," | |
| " Token = 0x%x, Status =%r\n", | |
| NodeList->IdMappingToken, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // 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] AcpiTableInfo Pointer to the ACPI table info structure. | |
| @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 CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo, | |
| 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; | |
| UINT64 NodeLength; | |
| ASSERT (Iort != NULL); | |
| Generator = (ACPI_IORT_GENERATOR *)This; | |
| PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE *)((UINT8 *)Iort + | |
| NodesStartOffset); | |
| while (NodeCount-- != 0) { | |
| NodeLength = GetPmcgNodeSize (NodeList); | |
| if (NodeLength > MAX_UINT16) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: PMCG Node length 0x%lx > MAX_UINT16. Status = %r\n", | |
| NodeLength, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // Populate the node header | |
| PmcgNode->Node.Type = EFI_ACPI_IORT_TYPE_PMCG; | |
| PmcgNode->Node.Length = (UINT16)NodeLength; | |
| PmcgNode->Node.NumIdMappings = NodeList->IdMappingCount; | |
| PmcgNode->Node.IdReference = (NodeList->IdMappingCount == 0) ? | |
| 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE); | |
| if (AcpiTableInfo->AcpiTableRevision < | |
| EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05) | |
| { | |
| PmcgNode->Node.Revision = 1; | |
| PmcgNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD; | |
| } else { | |
| PmcgNode->Node.Revision = 2; | |
| PmcgNode->Node.Identifier = NodeList->Identifier; | |
| } | |
| // 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) { | |
| if (NodeList->IdMappingToken == CM_NULL_TOKEN) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Id Mapping token," | |
| " Token = 0x%x, Status =%r\n", | |
| NodeList->IdMappingToken, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // 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; | |
| } | |
| /** Update the Memory Range Descriptor Array. | |
| This function retrieves the Memory Range Descriptor objects referenced by | |
| MemRangeDescToken and updates the Memory Range Descriptor array. | |
| @param [in] This Pointer to the table Generator. | |
| @param [in] CfgMgrProtocol Pointer to the Configuration Manager | |
| Protocol Interface. | |
| @param [in] DescArray Pointer to an array of Memory Range | |
| Descriptors. | |
| @param [in] DescCount Number of Id Descriptors. | |
| @param [in] DescToken Reference Token for retrieving the | |
| Memory Range Descriptor Array. | |
| @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 | |
| AddMemRangeDescArray ( | |
| IN CONST ACPI_TABLE_GENERATOR *CONST This, | |
| IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol, | |
| IN EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC *DescArray, | |
| IN UINT32 DescCount, | |
| IN CONST CM_OBJECT_TOKEN DescToken | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| CM_ARM_MEMORY_RANGE_DESCRIPTOR *MemRangeDesc; | |
| UINT32 MemRangeDescCount; | |
| ASSERT (DescArray != NULL); | |
| // Get the Id Mapping Array | |
| Status = GetEArmObjMemoryRangeDescriptor ( | |
| CfgMgrProtocol, | |
| DescToken, | |
| &MemRangeDesc, | |
| &MemRangeDescCount | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Failed to get Memory Range Descriptor array. Status = %r\n", | |
| Status | |
| )); | |
| return Status; | |
| } | |
| if (MemRangeDescCount < DescCount) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Failed to get the required number of Memory" | |
| " Range Descriptors.\n" | |
| )); | |
| return EFI_NOT_FOUND; | |
| } | |
| // Populate the Memory Range Descriptor array | |
| while (DescCount-- != 0) { | |
| DescArray->Base = MemRangeDesc->BaseAddress; | |
| DescArray->Length = MemRangeDesc->Length; | |
| DescArray->Reserved = EFI_ACPI_RESERVED_DWORD; | |
| DescArray++; | |
| MemRangeDesc++; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** Update the RMR Node Information. | |
| This function updates the RMR 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] AcpiTableInfo Pointer to the ACPI table info structure. | |
| @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 | |
| AddRmrNodes ( | |
| IN CONST ACPI_TABLE_GENERATOR *CONST This, | |
| IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol, | |
| IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo, | |
| IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort, | |
| IN CONST UINT32 NodesStartOffset, | |
| IN CONST CM_ARM_RMR_NODE *NodeList, | |
| IN UINT32 NodeCount | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE *RmrNode; | |
| EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray; | |
| EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC *MemRangeDescArray; | |
| UINT64 NodeLength; | |
| ASSERT (Iort != NULL); | |
| RmrNode = (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE *)((UINT8 *)Iort + | |
| NodesStartOffset); | |
| while (NodeCount-- != 0) { | |
| NodeLength = GetRmrNodeSize (NodeList); | |
| if (NodeLength > MAX_UINT16) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: RMR Node length 0x%lx > MAX_UINT16. Status = %r\n", | |
| NodeLength, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| if (NodeList->MemRangeDescCount == 0) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Memory Range Desc count = %d. Status = %r\n", | |
| NodeList->MemRangeDescCount, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| if (NodeList->MemRangeDescToken == CM_NULL_TOKEN) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Memory Range Descriptor token," | |
| " Token = 0x%x. Status = %r\n", | |
| NodeList->MemRangeDescToken, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // Populate the node header | |
| RmrNode->Node.Type = EFI_ACPI_IORT_TYPE_RMR; | |
| RmrNode->Node.Length = (UINT16)NodeLength; | |
| RmrNode->Node.Revision = 3; | |
| RmrNode->Node.Identifier = NodeList->Identifier; | |
| RmrNode->Node.NumIdMappings = NodeList->IdMappingCount; | |
| RmrNode->Node.IdReference = (NodeList->IdMappingCount == 0) ? | |
| 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE); | |
| // RMR specific data | |
| RmrNode->Flags = NodeList->Flags; | |
| RmrNode->NumMemRangeDesc = NodeList->MemRangeDescCount; | |
| RmrNode->MemRangeDescRef = (NodeList->MemRangeDescCount == 0) ? | |
| 0 : (sizeof (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE) + | |
| (NodeList->IdMappingCount * | |
| sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE))); | |
| if (NodeList->IdMappingCount > 0) { | |
| if (NodeList->IdMappingToken == CM_NULL_TOKEN) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Id Mapping token," | |
| " Token = 0x%x, Status =%r\n", | |
| NodeList->IdMappingToken, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // Ids for RMR node | |
| IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)RmrNode + | |
| RmrNode->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; | |
| } | |
| } | |
| // Memory Range Descriptors for RMR node | |
| MemRangeDescArray = (EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC *)( | |
| (UINT8 *)RmrNode + | |
| RmrNode->MemRangeDescRef | |
| ); | |
| Status = AddMemRangeDescArray ( | |
| This, | |
| CfgMgrProtocol, | |
| MemRangeDescArray, | |
| NodeList->MemRangeDescCount, | |
| NodeList->MemRangeDescToken | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Failed to Memory Range Descriptor Array. Status = %r\n", | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // Next RMR Node | |
| RmrNode = (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE *)((UINT8 *)RmrNode + | |
| RmrNode->Node.Length); | |
| NodeList++; | |
| } // RMR Node | |
| return EFI_SUCCESS; | |
| } | |
| /** Validates that the IORT nodes Identifier are unique. | |
| @param [in] NodeIndexer Pointer to the Node Indexer. | |
| @param [in] NodeCount Number of IORT Nodes. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER Identifier field not unique. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| ValidateNodeIdentifiers ( | |
| IN CONST IORT_NODE_INDEXER *CONST NodeIndexer, | |
| IN UINT32 NodeCount | |
| ) | |
| { | |
| UINT32 IndexI; | |
| UINT32 IndexJ; | |
| for (IndexI = 0; IndexI < NodeCount; IndexI++) { | |
| for (IndexJ = 0; IndexJ < NodeCount; IndexJ++) { | |
| if ((IndexI != IndexJ) && | |
| (NodeIndexer[IndexI].Identifier == NodeIndexer[IndexJ].Identifier)) | |
| { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: UID %d of Token %p matches with that of Token %p.\n", | |
| NodeIndexer[IndexI].Identifier, | |
| NodeIndexer[IndexI].Token, | |
| NodeIndexer[IndexJ].Token | |
| )); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| }// IndexJ | |
| } // IndexI | |
| 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; | |
| UINT64 TableSize; | |
| UINT64 NodeSize; | |
| UINT32 IortNodeCount; | |
| UINT32 ItsGroupNodeCount; | |
| UINT32 NamedComponentNodeCount; | |
| UINT32 RootComplexNodeCount; | |
| UINT32 SmmuV1V2NodeCount; | |
| UINT32 SmmuV3NodeCount; | |
| UINT32 PmcgNodeCount; | |
| UINT32 RmrNodeCount; | |
| UINT32 ItsGroupOffset; | |
| UINT32 NamedComponentOffset; | |
| UINT32 RootComplexOffset; | |
| UINT32 SmmuV1V2Offset; | |
| UINT32 SmmuV3Offset; | |
| UINT32 PmcgOffset; | |
| UINT32 RmrOffset; | |
| 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; | |
| CM_ARM_RMR_NODE *RmrNodeList; | |
| 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); | |
| RmrNodeCount = 0; | |
| 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; | |
| } | |
| if ((AcpiTableInfo->AcpiTableRevision > EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00) && | |
| (AcpiTableInfo->AcpiTableRevision < EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)) | |
| { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Revisions E (1), E.a(2),b(3),c(4) are not supported.\n" | |
| )); | |
| 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; | |
| if (AcpiTableInfo->AcpiTableRevision >= | |
| EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05) | |
| { | |
| // Get the RMR node info | |
| Status = GetEArmObjRmr ( | |
| CfgMgrProtocol, | |
| CM_NULL_TOKEN, | |
| &RmrNodeList, | |
| &RmrNodeCount | |
| ); | |
| if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Failed to get RMR Node Info. Status = %r\n", | |
| Status | |
| )); | |
| goto error_handler; | |
| } | |
| // Add the RMR node count | |
| IortNodeCount += RmrNodeCount; | |
| } | |
| // 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 = (UINT32)TableSize; | |
| // Size of ITS Group node list. | |
| NodeSize = GetSizeofItsGroupNodes ( | |
| ItsGroupOffset, | |
| ItsGroupNodeList, | |
| ItsGroupNodeCount, | |
| &NodeIndexer | |
| ); | |
| if (NodeSize > MAX_UINT32) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Size of Group Nodes. Status = %r\n", | |
| Status | |
| )); | |
| goto error_handler; | |
| } | |
| TableSize += NodeSize; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| " ItsGroupNodeCount = %d\n" \ | |
| " ItsGroupOffset = %d\n", | |
| ItsGroupNodeCount, | |
| ItsGroupOffset | |
| )); | |
| } | |
| // Named Component Nodes | |
| if (NamedComponentNodeCount > 0) { | |
| NamedComponentOffset = (UINT32)TableSize; | |
| // Size of Named Component node list. | |
| NodeSize = GetSizeofNamedComponentNodes ( | |
| NamedComponentOffset, | |
| NamedComponentNodeList, | |
| NamedComponentNodeCount, | |
| &NodeIndexer | |
| ); | |
| if (NodeSize > MAX_UINT32) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Size of Named Component Nodes. Status = %r\n", | |
| Status | |
| )); | |
| goto error_handler; | |
| } | |
| TableSize += NodeSize; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| " NamedComponentNodeCount = %d\n" \ | |
| " NamedComponentOffset = %d\n", | |
| NamedComponentNodeCount, | |
| NamedComponentOffset | |
| )); | |
| } | |
| // Root Complex Nodes | |
| if (RootComplexNodeCount > 0) { | |
| RootComplexOffset = (UINT32)TableSize; | |
| // Size of Root Complex node list. | |
| NodeSize = GetSizeofRootComplexNodes ( | |
| RootComplexOffset, | |
| RootComplexNodeList, | |
| RootComplexNodeCount, | |
| &NodeIndexer | |
| ); | |
| if (NodeSize > MAX_UINT32) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Size of Root Complex Nodes. Status = %r\n", | |
| Status | |
| )); | |
| goto error_handler; | |
| } | |
| TableSize += NodeSize; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| " RootComplexNodeCount = %d\n" \ | |
| " RootComplexOffset = %d\n", | |
| RootComplexNodeCount, | |
| RootComplexOffset | |
| )); | |
| } | |
| // SMMUv1/SMMUv2 Nodes | |
| if (SmmuV1V2NodeCount > 0) { | |
| SmmuV1V2Offset = (UINT32)TableSize; | |
| // Size of SMMUv1/SMMUv2 node list. | |
| NodeSize = GetSizeofSmmuV1V2Nodes ( | |
| SmmuV1V2Offset, | |
| SmmuV1V2NodeList, | |
| SmmuV1V2NodeCount, | |
| &NodeIndexer | |
| ); | |
| if (NodeSize > MAX_UINT32) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Size of SMMUv1/v2 Nodes. Status = %r\n", | |
| Status | |
| )); | |
| goto error_handler; | |
| } | |
| TableSize += NodeSize; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| " SmmuV1V2NodeCount = %d\n" \ | |
| " SmmuV1V2Offset = %d\n", | |
| SmmuV1V2NodeCount, | |
| SmmuV1V2Offset | |
| )); | |
| } | |
| // SMMUv3 Nodes | |
| if (SmmuV3NodeCount > 0) { | |
| SmmuV3Offset = (UINT32)TableSize; | |
| // Size of SMMUv3 node list. | |
| NodeSize = GetSizeofSmmuV3Nodes ( | |
| SmmuV3Offset, | |
| SmmuV3NodeList, | |
| SmmuV3NodeCount, | |
| &NodeIndexer | |
| ); | |
| if (NodeSize > MAX_UINT32) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Size of SMMUv3 Nodes. Status = %r\n", | |
| Status | |
| )); | |
| goto error_handler; | |
| } | |
| TableSize += NodeSize; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| " SmmuV3NodeCount = %d\n" \ | |
| " SmmuV3Offset = %d\n", | |
| SmmuV3NodeCount, | |
| SmmuV3Offset | |
| )); | |
| } | |
| // PMCG Nodes | |
| if (PmcgNodeCount > 0) { | |
| PmcgOffset = (UINT32)TableSize; | |
| // Size of PMCG node list. | |
| NodeSize = GetSizeofPmcgNodes ( | |
| PmcgOffset, | |
| PmcgNodeList, | |
| PmcgNodeCount, | |
| &NodeIndexer | |
| ); | |
| if (NodeSize > MAX_UINT32) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Size of PMCG Nodes. Status = %r\n", | |
| Status | |
| )); | |
| goto error_handler; | |
| } | |
| TableSize += NodeSize; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| " PmcgNodeCount = %d\n" \ | |
| " PmcgOffset = %d\n", | |
| PmcgNodeCount, | |
| PmcgOffset | |
| )); | |
| } | |
| // RMR Nodes | |
| if ((AcpiTableInfo->AcpiTableRevision >= | |
| EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05) && | |
| (RmrNodeCount > 0)) | |
| { | |
| RmrOffset = (UINT32)TableSize; | |
| // Size of RMR node list. | |
| NodeSize = GetSizeofRmrNodes ( | |
| RmrOffset, | |
| RmrNodeList, | |
| RmrNodeCount, | |
| &NodeIndexer | |
| ); | |
| if (NodeSize > MAX_UINT32) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Invalid Size of RMR Nodes. Status = %r\n", | |
| Status | |
| )); | |
| goto error_handler; | |
| } | |
| TableSize += NodeSize; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| " RmrNodeCount = %d\n" \ | |
| " RmrOffset = %d\n", | |
| RmrNodeCount, | |
| RmrOffset | |
| )); | |
| } | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "INFO: IORT:\n" \ | |
| " IortNodeCount = %d\n" \ | |
| " TableSize = 0x%lx\n", | |
| IortNodeCount, | |
| TableSize | |
| )); | |
| if (TableSize > MAX_UINT32) { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: IORT Table Size 0x%lx > MAX_UINT32," \ | |
| " Status = %r\n", | |
| TableSize, | |
| Status | |
| )); | |
| goto error_handler; | |
| } | |
| // Validate that the identifiers for the nodes are unique | |
| if (AcpiTableInfo->AcpiTableRevision >= | |
| EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05) | |
| { | |
| Status = ValidateNodeIdentifiers (Generator->NodeIndexer, IortNodeCount); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Node Identifier not unique. Status = %r\n", | |
| Status | |
| )); | |
| goto error_handler; | |
| } | |
| } | |
| // 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%lx\n", | |
| Iort, | |
| TableSize | |
| )); | |
| Status = AddAcpiHeader ( | |
| CfgMgrProtocol, | |
| This, | |
| &Iort->Header, | |
| AcpiTableInfo, | |
| (UINT32)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, | |
| AcpiTableInfo, | |
| 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, | |
| AcpiTableInfo, | |
| 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, | |
| AcpiTableInfo, | |
| 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, | |
| AcpiTableInfo, | |
| 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, | |
| AcpiTableInfo, | |
| 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, | |
| AcpiTableInfo, | |
| Iort, | |
| PmcgOffset, | |
| PmcgNodeList, | |
| PmcgNodeCount | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Failed to add PMCG Node. Status = %r\n", | |
| Status | |
| )); | |
| goto error_handler; | |
| } | |
| } | |
| if ((AcpiTableInfo->AcpiTableRevision >= | |
| EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05) && | |
| (RmrNodeCount > 0)) | |
| { | |
| Status = AddRmrNodes ( | |
| This, | |
| CfgMgrProtocol, | |
| AcpiTableInfo, | |
| Iort, | |
| RmrOffset, | |
| RmrNodeList, | |
| RmrNodeCount | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: IORT: Failed to add RMR 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_4_IO_REMAPPING_TABLE_SIGNATURE, | |
| // ACPI Table Revision supported by this Generator | |
| EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05, | |
| // Minimum supported ACPI Table Revision | |
| EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00, | |
| // 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 EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *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 EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = DeregisterAcpiTableGenerator (&IortGenerator.Header); | |
| DEBUG ((DEBUG_INFO, "Iort: Deregister Generator. Status = %r\n", Status)); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } |