4 Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
8 - IO Remapping Table, Platform Design Document,
9 Document number: ARM DEN 0049D, Issue D, March 2018
13 #include <IndustryStandard/IoRemappingTable.h>
14 #include <Library/AcpiLib.h>
15 #include <Library/BaseLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Protocol/AcpiTable.h>
20 // Module specific include files.
21 #include <AcpiTableGenerator.h>
22 #include <ConfigurationManagerObject.h>
23 #include <ConfigurationManagerHelper.h>
24 #include <Library/TableHelperLib.h>
25 #include <Protocol/ConfigurationManagerProtocol.h>
27 #include "IortGenerator.h"
29 /** ARM standard IORT Generator
32 The following Configuration Manager Object(s) are required by
35 - EArmObjNamedComponent
40 - EArmObjGicItsIdentifierArray
41 - EArmObjIdMappingArray
42 - EArmObjGicItsIdentifierArray
45 /** This macro expands to a function that retrieves the ITS
46 Group node information from the Configuration Manager.
54 /** This macro expands to a function that retrieves the
55 Named Component node information from the Configuration Manager.
59 EArmObjNamedComponent
,
60 CM_ARM_NAMED_COMPONENT_NODE
63 /** This macro expands to a function that retrieves the
64 Root Complex node information from the Configuration Manager.
69 CM_ARM_ROOT_COMPLEX_NODE
72 /** This macro expands to a function that retrieves the
73 SMMU v1/v2 node information from the Configuration Manager.
78 CM_ARM_SMMUV1_SMMUV2_NODE
81 /** This macro expands to a function that retrieves the
82 SMMU v3 node information from the Configuration Manager.
90 /** This macro expands to a function that retrieves the
91 PMCG node information from the Configuration Manager.
99 /** This macro expands to a function that retrieves the
100 ITS Identifier Array information from the Configuration Manager.
104 EArmObjGicItsIdentifierArray
,
105 CM_ARM_ITS_IDENTIFIER
108 /** This macro expands to a function that retrieves the
109 Id Mapping Array information from the Configuration Manager.
113 EArmObjIdMappingArray
,
117 /** This macro expands to a function that retrieves the
118 SMMU Interrupt Array information from the Configuration Manager.
122 EArmObjSmmuInterruptArray
,
123 CM_ARM_SMMU_INTERRUPT
126 /** Returns the size of the ITS Group node.
128 @param [in] Node Pointer to ITS Group node.
130 @retval Size of the ITS Group Node.
134 GetItsGroupNodeSize (
135 IN CONST CM_ARM_ITS_GROUP_NODE
* Node
138 ASSERT (Node
!= NULL
);
140 /* Size of ITS Group Node +
141 Size of ITS Identifier array
143 return sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
) +
144 (Node
->ItsIdCount
* sizeof (UINT32
));
147 /** Returns the total size required for the ITS Group nodes and
148 updates the Node Indexer.
150 This function calculates the size required for the node group
151 and also populates the Node Indexer array with offsets for the
154 @param [in] NodeStartOffset Offset from the start of the
155 IORT where this node group starts.
156 @param [in] NodeList Pointer to ITS Group node list.
157 @param [in] NodeCount Count of the ITS Group nodes.
158 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
160 @retval Total size of the ITS Group Nodes.
164 GetSizeofItsGroupNodes (
165 IN CONST UINT32 NodeStartOffset
,
166 IN CONST CM_ARM_ITS_GROUP_NODE
* NodeList
,
168 IN OUT IORT_NODE_INDEXER
** CONST NodeIndexer
173 ASSERT (NodeList
!= NULL
);
176 while (NodeCount
-- != 0) {
177 (*NodeIndexer
)->Token
= NodeList
->Token
;
178 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
179 (*NodeIndexer
)->Offset
= Size
+ NodeStartOffset
;
182 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
184 (*NodeIndexer
)->Token
,
185 (*NodeIndexer
)->Object
,
186 (*NodeIndexer
)->Offset
189 Size
+= GetItsGroupNodeSize (NodeList
);
196 /** Returns the size of the Named Component node.
198 @param [in] Node Pointer to Named Component node.
200 @retval Size of the Named Component node.
204 GetNamedComponentNodeSize (
205 IN CONST CM_ARM_NAMED_COMPONENT_NODE
* Node
208 ASSERT (Node
!= NULL
);
210 /* Size of Named Component node +
211 Size of ID mapping array +
212 Size of ASCII string + 'padding to 32-bit word aligned'.
214 return sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
) +
215 (Node
->IdMappingCount
*
216 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
)) +
217 ALIGN_VALUE (AsciiStrSize (Node
->ObjectName
), 4);
220 /** Returns the total size required for the Named Component nodes and
221 updates the Node Indexer.
223 This function calculates the size required for the node group
224 and also populates the Node Indexer array with offsets for the
227 @param [in] NodeStartOffset Offset from the start of the
228 IORT where this node group starts.
229 @param [in] NodeList Pointer to Named Component node list.
230 @param [in] NodeCount Count of the Named Component nodes.
231 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
233 @retval Total size of the Named Component nodes.
237 GetSizeofNamedComponentNodes (
238 IN CONST UINT32 NodeStartOffset
,
239 IN CONST CM_ARM_NAMED_COMPONENT_NODE
* NodeList
,
241 IN OUT IORT_NODE_INDEXER
** CONST NodeIndexer
246 ASSERT (NodeList
!= NULL
);
249 while (NodeCount
-- != 0) {
250 (*NodeIndexer
)->Token
= NodeList
->Token
;
251 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
252 (*NodeIndexer
)->Offset
= Size
+ NodeStartOffset
;
255 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
257 (*NodeIndexer
)->Token
,
258 (*NodeIndexer
)->Object
,
259 (*NodeIndexer
)->Offset
262 Size
+= GetNamedComponentNodeSize (NodeList
);
270 /** Returns the size of the Root Complex node.
272 @param [in] Node Pointer to Root Complex node.
274 @retval Size of the Root Complex node.
278 GetRootComplexNodeSize (
279 IN CONST CM_ARM_ROOT_COMPLEX_NODE
* Node
282 ASSERT (Node
!= NULL
);
284 /* Size of Root Complex node +
285 Size of ID mapping array
287 return sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
) +
288 (Node
->IdMappingCount
*
289 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
));
292 /** Returns the total size required for the Root Complex nodes and
293 updates the Node Indexer.
295 This function calculates the size required for the node group
296 and also populates the Node Indexer array with offsets for the
299 @param [in] NodeStartOffset Offset from the start of the
300 IORT where this node group starts.
301 @param [in] NodeList Pointer to Root Complex node list.
302 @param [in] NodeCount Count of the Root Complex nodes.
303 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
305 @retval Total size of the Root Complex nodes.
309 GetSizeofRootComplexNodes (
310 IN CONST UINT32 NodeStartOffset
,
311 IN CONST CM_ARM_ROOT_COMPLEX_NODE
* NodeList
,
313 IN OUT IORT_NODE_INDEXER
** CONST NodeIndexer
318 ASSERT (NodeList
!= NULL
);
321 while (NodeCount
-- != 0) {
322 (*NodeIndexer
)->Token
= NodeList
->Token
;
323 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
324 (*NodeIndexer
)->Offset
= Size
+ NodeStartOffset
;
327 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
329 (*NodeIndexer
)->Token
,
330 (*NodeIndexer
)->Object
,
331 (*NodeIndexer
)->Offset
334 Size
+= GetRootComplexNodeSize (NodeList
);
342 /** Returns the size of the SMMUv1/SMMUv2 node.
344 @param [in] Node Pointer to SMMUv1/SMMUv2 node list.
346 @retval Size of the SMMUv1/SMMUv2 node.
350 GetSmmuV1V2NodeSize (
351 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE
* Node
354 ASSERT (Node
!= NULL
);
356 /* Size of SMMU v1/SMMU v2 node +
357 Size of ID mapping array +
358 Size of context interrupt array +
359 Size of PMU interrupt array
361 return sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
) +
362 (Node
->IdMappingCount
*
363 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
)) +
364 (Node
->ContextInterruptCount
*
365 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
)) +
366 (Node
->PmuInterruptCount
*
367 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
));
370 /** Returns the total size required for the SMMUv1/SMMUv2 nodes and
371 updates the Node Indexer.
373 This function calculates the size required for the node group
374 and also populates the Node Indexer array with offsets for the
377 @param [in] NodeStartOffset Offset from the start of the
378 IORT where this node group starts.
379 @param [in] NodeList Pointer to SMMUv1/SMMUv2 node list.
380 @param [in] NodeCount Count of the SMMUv1/SMMUv2 nodes.
381 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
383 @retval Total size of the SMMUv1/SMMUv2 nodes.
387 GetSizeofSmmuV1V2Nodes (
388 IN CONST UINT32 NodeStartOffset
,
389 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE
* NodeList
,
391 IN OUT IORT_NODE_INDEXER
** CONST NodeIndexer
396 ASSERT (NodeList
!= NULL
);
399 while (NodeCount
-- != 0) {
400 (*NodeIndexer
)->Token
= NodeList
->Token
;
401 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
402 (*NodeIndexer
)->Offset
= Size
+ NodeStartOffset
;
405 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
407 (*NodeIndexer
)->Token
,
408 (*NodeIndexer
)->Object
,
409 (*NodeIndexer
)->Offset
412 Size
+= GetSmmuV1V2NodeSize (NodeList
);
419 /** Returns the size of the SMMUv3 node.
421 @param [in] Node Pointer to SMMUv3 node list.
423 @retval Total size of the SMMUv3 nodes.
428 IN CONST CM_ARM_SMMUV3_NODE
* Node
431 ASSERT (Node
!= NULL
);
433 /* Size of SMMU v1/SMMU v2 node +
434 Size of ID mapping array
436 return sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
) +
437 (Node
->IdMappingCount
*
438 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
));
441 /** Returns the total size required for the SMMUv3 nodes and
442 updates the Node Indexer.
444 This function calculates the size required for the node group
445 and also populates the Node Indexer array with offsets for the
448 @param [in] NodeStartOffset Offset from the start of the
449 IORT where this node group starts.
450 @param [in] NodeList Pointer to SMMUv3 node list.
451 @param [in] NodeCount Count of the SMMUv3 nodes.
452 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
454 @retval Total size of the SMMUv3 nodes.
458 GetSizeofSmmuV3Nodes (
459 IN CONST UINT32 NodeStartOffset
,
460 IN CONST CM_ARM_SMMUV3_NODE
* NodeList
,
462 IN OUT IORT_NODE_INDEXER
** CONST NodeIndexer
467 ASSERT (NodeList
!= NULL
);
470 while (NodeCount
-- != 0) {
471 (*NodeIndexer
)->Token
= NodeList
->Token
;
472 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
473 (*NodeIndexer
)->Offset
= Size
+ NodeStartOffset
;
476 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
478 (*NodeIndexer
)->Token
,
479 (*NodeIndexer
)->Object
,
480 (*NodeIndexer
)->Offset
483 Size
+= GetSmmuV3NodeSize (NodeList
);
490 /** Returns the size of the PMCG node.
492 @param [in] Node Pointer to PMCG node.
494 @retval Size of the PMCG node.
499 IN CONST CM_ARM_PMCG_NODE
* Node
502 ASSERT (Node
!= NULL
);
504 /* Size of PMCG node +
505 Size of ID mapping array
507 return sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
) +
508 (Node
->IdMappingCount
*
509 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
));
512 /** Returns the total size required for the PMCG nodes and
513 updates the Node Indexer.
515 This function calculates the size required for the node group
516 and also populates the Node Indexer array with offsets for the
519 @param [in] NodeStartOffset Offset from the start of the
520 IORT where this node group starts.
521 @param [in] NodeList Pointer to PMCG node list.
522 @param [in] NodeCount Count of the PMCG nodes.
523 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
525 @retval Total size of the PMCG nodes.
530 IN CONST UINT32 NodeStartOffset
,
531 IN CONST CM_ARM_PMCG_NODE
* NodeList
,
533 IN OUT IORT_NODE_INDEXER
** CONST NodeIndexer
538 ASSERT (NodeList
!= NULL
);
541 while (NodeCount
-- != 0) {
542 (*NodeIndexer
)->Token
= NodeList
->Token
;
543 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
544 (*NodeIndexer
)->Offset
= Size
+ NodeStartOffset
;
547 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
549 (*NodeIndexer
)->Token
,
550 (*NodeIndexer
)->Object
,
551 (*NodeIndexer
)->Offset
554 Size
+= GetPmcgNodeSize (NodeList
);
561 /** Returns the offset of the Node referenced by the Token.
563 @param [in] NodeIndexer Pointer to node indexer array.
564 @param [in] NodeCount Count of the nodes.
565 @param [in] Token Reference token for the node.
566 @param [out] NodeOffset Offset of the node from the
567 start of the IORT table.
569 @retval EFI_SUCCESS Success.
570 @retval EFI_NOT_FOUND No matching token reference
571 found in node indexer array.
575 GetNodeOffsetReferencedByToken (
576 IN IORT_NODE_INDEXER
* NodeIndexer
,
578 IN CM_OBJECT_TOKEN Token
,
579 OUT UINT32
* NodeOffset
584 "IORT: Node Indexer: Search Token = %p\n",
587 while (NodeCount
-- != 0) {
590 "IORT: Node Indexer: NodeIndexer->Token = %p, Offset = %d\n",
594 if (NodeIndexer
->Token
== Token
) {
595 *NodeOffset
= NodeIndexer
->Offset
;
598 "IORT: Node Indexer: Token = %p, Found\n",
607 "IORT: Node Indexer: Token = %p, Not Found\n",
610 return EFI_NOT_FOUND
;
613 /** Update the Id Mapping Array.
615 This function retrieves the Id Mapping Array object referenced by the
616 IdMappingToken and updates the IdMapArray.
618 @param [in] This Pointer to the table Generator.
619 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
621 @param [in] IdMapArray Pointer to an array of Id Mappings.
622 @param [in] IdCount Number of Id Mappings.
623 @param [in] IdMappingToken Reference Token for retrieving the
624 Id Mapping Array object.
626 @retval EFI_SUCCESS Table generated successfully.
627 @retval EFI_INVALID_PARAMETER A parameter is invalid.
628 @retval EFI_NOT_FOUND The required object was not found.
633 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
634 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
635 IN EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
,
637 IN CONST CM_OBJECT_TOKEN IdMappingToken
641 CM_ARM_ID_MAPPING
* IdMappings
;
642 UINT32 IdMappingCount
;
643 ACPI_IORT_GENERATOR
* Generator
;
645 ASSERT (IdMapArray
!= NULL
);
647 Generator
= (ACPI_IORT_GENERATOR
*)This
;
649 // Get the Id Mapping Array
650 Status
= GetEArmObjIdMappingArray (
656 if (EFI_ERROR (Status
)) {
659 "ERROR: IORT: Failed to get Id Mapping array. Status = %r\n",
665 if (IdMappingCount
< IdCount
) {
668 "ERROR: IORT: Failed to get the required number of Id Mappings.\n"
670 return EFI_NOT_FOUND
;
673 // Populate the Id Mapping array
674 while (IdCount
-- != 0) {
675 Status
= GetNodeOffsetReferencedByToken (
676 Generator
->NodeIndexer
,
677 Generator
->IortNodeCount
,
678 IdMappings
->OutputReferenceToken
,
679 &IdMapArray
->OutputReference
681 if (EFI_ERROR (Status
)) {
684 "ERROR: IORT: Failed to get Output Reference for ITS Identifier array."
685 "Reference Token = %p"
687 IdMappings
->OutputReferenceToken
,
693 IdMapArray
->InputBase
= IdMappings
->InputBase
;
694 IdMapArray
->NumIds
= IdMappings
->NumIds
;
695 IdMapArray
->OutputBase
= IdMappings
->OutputBase
;
696 IdMapArray
->Flags
= IdMappings
->Flags
;
700 } // Id Mapping array
705 /** Update the ITS Group Node Information.
707 @param [in] This Pointer to the table Generator.
708 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
710 @param [in] Iort Pointer to IORT table structure.
711 @param [in] NodesStartOffset Offset for the start of the ITS Group
713 @param [in] NodeList Pointer to an array of ITS Group Node
715 @param [in] NodeCount Number of ITS Group Node Objects.
717 @retval EFI_SUCCESS Table generated successfully.
718 @retval EFI_INVALID_PARAMETER A parameter is invalid.
719 @retval EFI_NOT_FOUND The required object was not found.
724 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
725 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
726 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
727 IN CONST UINT32 NodesStartOffset
,
728 IN CONST CM_ARM_ITS_GROUP_NODE
* NodeList
,
733 EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
* ItsGroupNode
;
735 CM_ARM_ITS_IDENTIFIER
* ItsIdentifier
;
736 UINT32 ItsIdentifierCount
;
739 ASSERT (Iort
!= NULL
);
741 ItsGroupNode
= (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
*)((UINT8
*)Iort
+
744 while (NodeCount
-- != 0) {
745 // Populate the node header
746 ItsGroupNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_ITS_GROUP
;
747 ItsGroupNode
->Node
.Length
= GetItsGroupNodeSize (NodeList
);
748 ItsGroupNode
->Node
.Revision
= 0;
749 ItsGroupNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
750 ItsGroupNode
->Node
.NumIdMappings
= 0;
751 ItsGroupNode
->Node
.IdReference
= 0;
753 // IORT specific data
754 ItsGroupNode
->NumItsIdentifiers
= NodeList
->ItsIdCount
;
755 ItsIds
= (UINT32
*)((UINT8
*)ItsGroupNode
+
756 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
));
758 Status
= GetEArmObjGicItsIdentifierArray (
760 NodeList
->ItsIdToken
,
764 if (EFI_ERROR (Status
)) {
767 "ERROR: IORT: Failed to get ITS Identifier array. Status = %r\n",
773 if (ItsIdentifierCount
< ItsGroupNode
->NumItsIdentifiers
) {
776 "ERROR: IORT: Failed to get the required number of ITS Identifiers.\n"
778 return EFI_NOT_FOUND
;
781 // Populate the ITS identifier array
782 for (IdIndex
= 0; IdIndex
< ItsGroupNode
->NumItsIdentifiers
; IdIndex
++) {
783 ItsIds
[IdIndex
] = ItsIdentifier
[IdIndex
].ItsId
;
784 } // ITS identifier array
786 // Next IORT Group Node
787 ItsGroupNode
= (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
*)((UINT8
*)ItsGroupNode
+
788 ItsGroupNode
->Node
.Length
);
795 /** Update the Named Component Node Information.
797 This function updates the Named Component node information in the IORT
800 @param [in] This Pointer to the table Generator.
801 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
803 @param [in] Iort Pointer to IORT table structure.
804 @param [in] NodesStartOffset Offset for the start of the Named
806 @param [in] NodeList Pointer to an array of Named Component
808 @param [in] NodeCount Number of Named Component Node Objects.
810 @retval EFI_SUCCESS Table generated successfully.
811 @retval EFI_INVALID_PARAMETER A parameter is invalid.
812 @retval EFI_NOT_FOUND The required object was not found.
816 AddNamedComponentNodes (
817 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
818 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
819 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
820 IN CONST UINT32 NodesStartOffset
,
821 IN CONST CM_ARM_NAMED_COMPONENT_NODE
* NodeList
,
826 EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
* NcNode
;
827 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
828 UINT32 ObjectNameLenght
;
831 ASSERT (Iort
!= NULL
);
833 NcNode
= (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
*)((UINT8
*)Iort
+
836 while (NodeCount
-- != 0) {
837 // Populate the node header
838 NcNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_NAMED_COMP
;
839 NcNode
->Node
.Length
=
840 GetNamedComponentNodeSize (NodeList
);
841 NcNode
->Node
.Revision
= 2;
842 NcNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
843 NcNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
845 ObjectNameLenght
= AsciiStrLen (NodeList
->ObjectName
) + 1;
846 NcNode
->Node
.IdReference
=
847 sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
) +
848 (ALIGN_VALUE (ObjectNameLenght
, 4));
850 // Named Component specific data
851 NcNode
->Flags
= NodeList
->Flags
;
852 NcNode
->CacheCoherent
= NodeList
->CacheCoherent
;
853 NcNode
->AllocationHints
= NodeList
->AllocationHints
;
854 NcNode
->Reserved
= EFI_ACPI_RESERVED_WORD
;
855 NcNode
->MemoryAccessFlags
= NodeList
->MemoryAccessFlags
;
856 NcNode
->AddressSizeLimit
= NodeList
->AddressSizeLimit
;
858 // Copy the object name
859 ObjectName
= (CHAR8
*)((UINT8
*)NcNode
+
860 sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
));
861 Status
= AsciiStrCpyS (
866 if (EFI_ERROR (Status
)) {
869 "ERROR: IORT: Failed to copy Object Name. Status = %r\n",
875 if ((NodeList
->IdMappingCount
> 0) &&
876 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
877 // Ids for Named Component
878 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)NcNode
+
879 NcNode
->Node
.IdReference
);
881 Status
= AddIdMappingArray (
885 NodeList
->IdMappingCount
,
886 NodeList
->IdMappingToken
888 if (EFI_ERROR (Status
)) {
891 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
898 // Next Named Component Node
899 NcNode
= (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
*)((UINT8
*)NcNode
+
900 NcNode
->Node
.Length
);
902 } // Named Component Node
907 /** Update the Root Complex Node Information.
909 This function updates the Root Complex node information in the IORT table.
911 @param [in] This Pointer to the table Generator.
912 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
914 @param [in] Iort Pointer to IORT table structure.
915 @param [in] NodesStartOffset Offset for the start of the Root Complex
917 @param [in] NodeList Pointer to an array of Root Complex Node
919 @param [in] NodeCount Number of Root Complex Node Objects.
921 @retval EFI_SUCCESS Table generated successfully.
922 @retval EFI_INVALID_PARAMETER A parameter is invalid.
923 @retval EFI_NOT_FOUND The required object was not found.
927 AddRootComplexNodes (
928 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
929 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
930 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
931 IN CONST UINT32 NodesStartOffset
,
932 IN CONST CM_ARM_ROOT_COMPLEX_NODE
* NodeList
,
937 EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
* RcNode
;
938 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
940 ASSERT (Iort
!= NULL
);
942 RcNode
= (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
*)((UINT8
*)Iort
+
945 while (NodeCount
-- != 0) {
946 // Populate the node header
947 RcNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_ROOT_COMPLEX
;
948 RcNode
->Node
.Length
= GetRootComplexNodeSize (NodeList
);
949 RcNode
->Node
.Revision
= 1;
950 RcNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
951 RcNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
952 RcNode
->Node
.IdReference
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
);
954 // Root Complex specific data
955 RcNode
->CacheCoherent
= NodeList
->CacheCoherent
;
956 RcNode
->AllocationHints
= NodeList
->AllocationHints
;
957 RcNode
->Reserved
= EFI_ACPI_RESERVED_WORD
;
958 RcNode
->MemoryAccessFlags
= NodeList
->MemoryAccessFlags
;
959 RcNode
->AtsAttribute
= NodeList
->AtsAttribute
;
960 RcNode
->PciSegmentNumber
= NodeList
->PciSegmentNumber
;
961 RcNode
->MemoryAddressSize
= NodeList
->MemoryAddressSize
;
962 RcNode
->Reserved1
[0] = EFI_ACPI_RESERVED_BYTE
;
963 RcNode
->Reserved1
[1] = EFI_ACPI_RESERVED_BYTE
;
964 RcNode
->Reserved1
[2] = EFI_ACPI_RESERVED_BYTE
;
966 if ((NodeList
->IdMappingCount
> 0) &&
967 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
968 // Ids for Root Complex
969 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)RcNode
+
970 RcNode
->Node
.IdReference
);
971 Status
= AddIdMappingArray (
975 NodeList
->IdMappingCount
,
976 NodeList
->IdMappingToken
978 if (EFI_ERROR (Status
)) {
981 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
988 // Next Root Complex Node
989 RcNode
= (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
*)((UINT8
*)RcNode
+
990 RcNode
->Node
.Length
);
992 } // Root Complex Node
997 /** Update the SMMU Interrupt Array.
999 This function retrieves the InterruptArray object referenced by the
1000 InterruptToken and updates the SMMU InterruptArray.
1002 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1004 @param [in, out] InterruptArray Pointer to an array of Interrupts.
1005 @param [in] InterruptCount Number of entries in the InterruptArray.
1006 @param [in] InterruptToken Reference Token for retrieving the SMMU
1007 InterruptArray object.
1009 @retval EFI_SUCCESS Table generated successfully.
1010 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1011 @retval EFI_NOT_FOUND The required object was not found.
1015 AddSmmuInterrruptArray (
1016 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1017 IN OUT EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
* InterruptArray
,
1018 IN UINT32 InterruptCount
,
1019 IN CONST CM_OBJECT_TOKEN InterruptToken
1023 CM_ARM_SMMU_INTERRUPT
* SmmuInterrupt
;
1024 UINT32 SmmuInterruptCount
;
1026 ASSERT (InterruptArray
!= NULL
);
1028 // Get the SMMU Interrupt Array
1029 Status
= GetEArmObjSmmuInterruptArray (
1035 if (EFI_ERROR (Status
)) {
1038 "ERROR: IORT: Failed to get SMMU Interrupt array. Status = %r\n",
1044 if (SmmuInterruptCount
< InterruptCount
) {
1047 "ERROR: IORT: Failed to get the required number of SMMU Interrupts.\n"
1049 return EFI_NOT_FOUND
;
1052 // Populate the Id Mapping array
1053 while (InterruptCount
-- != 0) {
1054 InterruptArray
->Interrupt
= SmmuInterrupt
->Interrupt
;
1055 InterruptArray
->InterruptFlags
= SmmuInterrupt
->Flags
;
1058 } // Id Mapping array
1063 /** Update the SMMU v1/v2 Node Information.
1065 @param [in] This Pointer to the table Generator.
1066 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1068 @param [in] Iort Pointer to IORT table structure.
1069 @param [in] NodesStartOffset Offset for the start of the SMMU v1/v2
1071 @param [in] NodeList Pointer to an array of SMMU v1/v2 Node
1073 @param [in] NodeCount Number of SMMU v1/v2 Node Objects.
1075 @retval EFI_SUCCESS Table generated successfully.
1076 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1077 @retval EFI_NOT_FOUND The required object was not found.
1082 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1083 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1084 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
1085 IN CONST UINT32 NodesStartOffset
,
1086 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE
* NodeList
,
1091 EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
* SmmuNode
;
1092 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
1094 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
* ContextInterruptArray
;
1095 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
* PmuInterruptArray
;
1097 ASSERT (Iort
!= NULL
);
1099 SmmuNode
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
*)((UINT8
*)Iort
+
1102 while (NodeCount
-- != 0) {
1103 // Populate the node header
1104 SmmuNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_SMMUv1v2
;
1105 SmmuNode
->Node
.Length
= GetSmmuV1V2NodeSize (NodeList
);
1106 SmmuNode
->Node
.Revision
= 0;
1107 SmmuNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
1108 SmmuNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1109 SmmuNode
->Node
.IdReference
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
) +
1110 (NodeList
->ContextInterruptCount
*
1111 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
)) +
1112 (NodeList
->PmuInterruptCount
*
1113 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
));
1115 // SMMU v1/v2 specific data
1116 SmmuNode
->Base
= NodeList
->BaseAddress
;
1117 SmmuNode
->Span
= NodeList
->Span
;
1118 SmmuNode
->Model
= NodeList
->Model
;
1119 SmmuNode
->Flags
= NodeList
->Flags
;
1121 // Reference to Global Interrupt Array
1122 SmmuNode
->GlobalInterruptArrayRef
=
1123 OFFSET_OF (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
, SMMU_NSgIrpt
);
1125 // Context Interrupt
1126 SmmuNode
->NumContextInterrupts
= NodeList
->ContextInterruptCount
;
1127 SmmuNode
->ContextInterruptArrayRef
=
1128 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
);
1129 ContextInterruptArray
=
1130 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
*)((UINT8
*)SmmuNode
+
1131 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
));
1134 SmmuNode
->NumPmuInterrupts
= NodeList
->PmuInterruptCount
;
1135 SmmuNode
->PmuInterruptArrayRef
= SmmuNode
->ContextInterruptArrayRef
+
1136 (NodeList
->ContextInterruptCount
*
1137 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
));
1139 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
*)((UINT8
*)SmmuNode
+
1140 SmmuNode
->PmuInterruptArrayRef
);
1142 SmmuNode
->SMMU_NSgIrpt
= NodeList
->SMMU_NSgIrpt
;
1143 SmmuNode
->SMMU_NSgIrptFlags
= NodeList
->SMMU_NSgIrptFlags
;
1144 SmmuNode
->SMMU_NSgCfgIrpt
= NodeList
->SMMU_NSgCfgIrpt
;
1145 SmmuNode
->SMMU_NSgCfgIrptFlags
= NodeList
->SMMU_NSgCfgIrptFlags
;
1147 // Add Context Interrupt Array
1148 Status
= AddSmmuInterrruptArray (
1150 ContextInterruptArray
,
1151 SmmuNode
->NumContextInterrupts
,
1152 NodeList
->ContextInterruptToken
1154 if (EFI_ERROR (Status
)) {
1157 "ERROR: IORT: Failed to Context Interrupt Array. Status = %r\n",
1163 // Add PMU Interrupt Array
1164 if ((SmmuNode
->NumPmuInterrupts
> 0) &&
1165 (NodeList
->PmuInterruptToken
!= CM_NULL_TOKEN
)) {
1166 Status
= AddSmmuInterrruptArray (
1169 SmmuNode
->NumPmuInterrupts
,
1170 NodeList
->PmuInterruptToken
1172 if (EFI_ERROR (Status
)) {
1175 "ERROR: IORT: Failed to PMU Interrupt Array. Status = %r\n",
1182 if ((NodeList
->IdMappingCount
> 0) &&
1183 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
1184 // Ids for SMMU v1/v2 Node
1185 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)SmmuNode
+
1186 SmmuNode
->Node
.IdReference
);
1187 Status
= AddIdMappingArray (
1191 NodeList
->IdMappingCount
,
1192 NodeList
->IdMappingToken
1194 if (EFI_ERROR (Status
)) {
1197 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1203 // Next SMMU v1/v2 Node
1204 SmmuNode
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
*)((UINT8
*)SmmuNode
+
1205 SmmuNode
->Node
.Length
);
1207 } // SMMU v1/v2 Node
1212 /** Update the SMMUv3 Node Information.
1214 This function updates the SMMUv3 node information in the IORT table.
1216 @param [in] This Pointer to the table Generator.
1217 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1219 @param [in] Iort Pointer to IORT table structure.
1220 @param [in] NodesStartOffset Offset for the start of the SMMUv3 Nodes.
1221 @param [in] NodeList Pointer to an array of SMMUv3 Node Objects.
1222 @param [in] NodeCount Number of SMMUv3 Node Objects.
1224 @retval EFI_SUCCESS Table generated successfully.
1225 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1226 @retval EFI_NOT_FOUND The required object was not found.
1231 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1232 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1233 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
1234 IN CONST UINT32 NodesStartOffset
,
1235 IN CONST CM_ARM_SMMUV3_NODE
* NodeList
,
1240 EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
* SmmuV3Node
;
1241 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
1243 ASSERT (Iort
!= NULL
);
1245 SmmuV3Node
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
*)((UINT8
*)Iort
+
1248 while (NodeCount
-- != 0) {
1249 // Populate the node header
1250 SmmuV3Node
->Node
.Type
= EFI_ACPI_IORT_TYPE_SMMUv3
;
1251 SmmuV3Node
->Node
.Length
= GetSmmuV3NodeSize (NodeList
);
1252 SmmuV3Node
->Node
.Revision
= 2;
1253 SmmuV3Node
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
1254 SmmuV3Node
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1255 SmmuV3Node
->Node
.IdReference
=
1256 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
);
1258 // SMMUv3 specific data
1259 SmmuV3Node
->Base
= NodeList
->BaseAddress
;
1260 SmmuV3Node
->Flags
= NodeList
->Flags
;
1261 SmmuV3Node
->Reserved
= EFI_ACPI_RESERVED_WORD
;
1262 SmmuV3Node
->VatosAddress
= NodeList
->VatosAddress
;
1263 SmmuV3Node
->Model
= NodeList
->Model
;
1264 SmmuV3Node
->Event
= NodeList
->EventInterrupt
;
1265 SmmuV3Node
->Pri
= NodeList
->PriInterrupt
;
1266 SmmuV3Node
->Gerr
= NodeList
->GerrInterrupt
;
1267 SmmuV3Node
->Sync
= NodeList
->SyncInterrupt
;
1269 if ((SmmuV3Node
->Flags
& EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN
) != 0) {
1270 // The Proximity Domain Valid flag is set to 1
1271 SmmuV3Node
->ProximityDomain
= NodeList
->ProximityDomain
;
1273 SmmuV3Node
->ProximityDomain
= 0;
1276 if ((SmmuV3Node
->Event
!= 0) && (SmmuV3Node
->Pri
!= 0) &&
1277 (SmmuV3Node
->Gerr
!= 0) && (SmmuV3Node
->Sync
!= 0)) {
1278 // If all the SMMU control interrupts are GSIV based,
1279 // the DeviceID mapping index field is ignored.
1280 SmmuV3Node
->DeviceIdMappingIndex
= 0;
1282 SmmuV3Node
->DeviceIdMappingIndex
= NodeList
->DeviceIdMappingIndex
;
1285 if ((NodeList
->IdMappingCount
> 0) &&
1286 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
1287 // Ids for SMMUv3 node
1288 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)SmmuV3Node
+
1289 SmmuV3Node
->Node
.IdReference
);
1290 Status
= AddIdMappingArray (
1294 NodeList
->IdMappingCount
,
1295 NodeList
->IdMappingToken
1297 if (EFI_ERROR (Status
)) {
1300 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1308 SmmuV3Node
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
*)((UINT8
*)SmmuV3Node
+
1309 SmmuV3Node
->Node
.Length
);
1316 /** Update the PMCG Node Information.
1318 This function updates the PMCG node information in the IORT table.
1320 @param [in] This Pointer to the table Generator.
1321 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1323 @param [in] Iort Pointer to IORT table structure.
1324 @param [in] NodesStartOffset Offset for the start of the PMCG Nodes.
1325 @param [in] NodeList Pointer to an array of PMCG Node Objects.
1326 @param [in] NodeCount Number of PMCG Node Objects.
1328 @retval EFI_SUCCESS Table generated successfully.
1329 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1330 @retval EFI_NOT_FOUND The required object was not found.
1335 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1336 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1337 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
1338 IN CONST UINT32 NodesStartOffset
,
1339 IN CONST CM_ARM_PMCG_NODE
* NodeList
,
1344 EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
* PmcgNode
;
1345 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
1346 ACPI_IORT_GENERATOR
* Generator
;
1348 ASSERT (Iort
!= NULL
);
1350 Generator
= (ACPI_IORT_GENERATOR
*)This
;
1351 PmcgNode
= (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
*)((UINT8
*)Iort
+
1354 while (NodeCount
-- != 0) {
1355 // Populate the node header
1356 PmcgNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_PMCG
;
1357 PmcgNode
->Node
.Length
= GetPmcgNodeSize (NodeList
);
1358 PmcgNode
->Node
.Revision
= 1;
1359 PmcgNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
1360 PmcgNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1361 PmcgNode
->Node
.IdReference
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
);
1363 // PMCG specific data
1364 PmcgNode
->Base
= NodeList
->BaseAddress
;
1365 PmcgNode
->OverflowInterruptGsiv
= NodeList
->OverflowInterrupt
;
1366 PmcgNode
->Page1Base
= NodeList
->Page1BaseAddress
;
1368 Status
= GetNodeOffsetReferencedByToken (
1369 Generator
->NodeIndexer
,
1370 Generator
->IortNodeCount
,
1371 NodeList
->ReferenceToken
,
1372 &PmcgNode
->NodeReference
1374 if (EFI_ERROR (Status
)) {
1377 "ERROR: IORT: Failed to get Output Reference for PMCG Node."
1378 "Reference Token = %p"
1380 NodeList
->ReferenceToken
,
1386 if ((NodeList
->IdMappingCount
> 0) &&
1387 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
1388 // Ids for PMCG node
1389 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)PmcgNode
+
1390 PmcgNode
->Node
.IdReference
);
1392 Status
= AddIdMappingArray (
1396 NodeList
->IdMappingCount
,
1397 NodeList
->IdMappingToken
1399 if (EFI_ERROR (Status
)) {
1402 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1410 PmcgNode
= (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
*)((UINT8
*)PmcgNode
+
1411 PmcgNode
->Node
.Length
);
1418 /** Construct the IORT ACPI table.
1420 This function invokes the Configuration Manager protocol interface
1421 to get the required hardware information for generating the ACPI
1424 If this function allocates any resources then they must be freed
1425 in the FreeXXXXTableResources function.
1427 @param [in] This Pointer to the table generator.
1428 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1429 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1431 @param [out] Table Pointer to the constructed ACPI Table.
1433 @retval EFI_SUCCESS Table generated successfully.
1434 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1435 @retval EFI_NOT_FOUND The required object was not found.
1436 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
1437 Manager is less than the Object size for the
1444 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1445 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
1446 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1447 OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
1452 UINT32 IortNodeCount
;
1454 UINT32 ItsGroupNodeCount
;
1455 UINT32 NamedComponentNodeCount
;
1456 UINT32 RootComplexNodeCount
;
1457 UINT32 SmmuV1V2NodeCount
;
1458 UINT32 SmmuV3NodeCount
;
1459 UINT32 PmcgNodeCount
;
1461 UINT32 ItsGroupOffset
;
1462 UINT32 NamedComponentOffset
;
1463 UINT32 RootComplexOffset
;
1464 UINT32 SmmuV1V2Offset
;
1465 UINT32 SmmuV3Offset
;
1468 CM_ARM_ITS_GROUP_NODE
* ItsGroupNodeList
;
1469 CM_ARM_NAMED_COMPONENT_NODE
* NamedComponentNodeList
;
1470 CM_ARM_ROOT_COMPLEX_NODE
* RootComplexNodeList
;
1471 CM_ARM_SMMUV1_SMMUV2_NODE
* SmmuV1V2NodeList
;
1472 CM_ARM_SMMUV3_NODE
* SmmuV3NodeList
;
1473 CM_ARM_PMCG_NODE
* PmcgNodeList
;
1475 EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
;
1476 IORT_NODE_INDEXER
* NodeIndexer
;
1477 ACPI_IORT_GENERATOR
* Generator
;
1479 ASSERT (This
!= NULL
);
1480 ASSERT (AcpiTableInfo
!= NULL
);
1481 ASSERT (CfgMgrProtocol
!= NULL
);
1482 ASSERT (Table
!= NULL
);
1483 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
1484 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
1486 if ((AcpiTableInfo
->AcpiTableRevision
< This
->MinAcpiTableRevision
) ||
1487 (AcpiTableInfo
->AcpiTableRevision
> This
->AcpiTableRevision
)) {
1490 "ERROR: IORT: Requested table revision = %d, is not supported."
1491 "Supported table revision: Minimum = %d, Maximum = %d\n",
1492 AcpiTableInfo
->AcpiTableRevision
,
1493 This
->MinAcpiTableRevision
,
1494 This
->AcpiTableRevision
1496 return EFI_INVALID_PARAMETER
;
1499 Generator
= (ACPI_IORT_GENERATOR
*)This
;
1502 // Get the ITS group node info
1503 Status
= GetEArmObjItsGroup (
1509 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1512 "ERROR: IORT: Failed to get ITS Group Node Info. Status = %r\n",
1518 // Add the ITS group node count
1519 IortNodeCount
= ItsGroupNodeCount
;
1521 // Get the Named component node info
1522 Status
= GetEArmObjNamedComponent (
1525 &NamedComponentNodeList
,
1526 &NamedComponentNodeCount
1528 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1531 "ERROR: IORT: Failed to get Named Component Node Info. Status = %r\n",
1537 // Add the Named Component group count
1538 IortNodeCount
+= NamedComponentNodeCount
;
1540 // Get the Root complex node info
1541 Status
= GetEArmObjRootComplex (
1544 &RootComplexNodeList
,
1545 &RootComplexNodeCount
1547 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1550 "ERROR: IORT: Failed to get Root Complex Node Info. Status = %r\n",
1556 // Add the Root Complex node count
1557 IortNodeCount
+= RootComplexNodeCount
;
1559 // Get the SMMU v1/v2 node info
1560 Status
= GetEArmObjSmmuV1SmmuV2 (
1566 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1569 "ERROR: IORT: Failed to get SMMUv1/SMMUv2 Node Info. Status = %r\n",
1575 // Add the SMMU v1/v2 node count
1576 IortNodeCount
+= SmmuV1V2NodeCount
;
1578 // Get the SMMUv3 node info
1579 Status
= GetEArmObjSmmuV3 (
1585 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1588 "ERROR: IORT: Failed to get SMMUv3 Node Info. Status = %r\n",
1594 // Add the SMMUv3 node count
1595 IortNodeCount
+= SmmuV3NodeCount
;
1597 // Get the PMCG node info
1598 Status
= GetEArmObjPmcg (
1604 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1607 "ERROR: IORT: Failed to get PMCG Node Info. Status = %r\n",
1613 // Add the PMCG node count
1614 IortNodeCount
+= PmcgNodeCount
;
1616 // Allocate Node Indexer array
1617 NodeIndexer
= (IORT_NODE_INDEXER
*)AllocateZeroPool (
1618 (sizeof (IORT_NODE_INDEXER
) *
1621 if (NodeIndexer
== NULL
) {
1622 Status
= EFI_OUT_OF_RESOURCES
;
1625 "ERROR: IORT: Failed to allocate memory for Node Indexer" \
1632 DEBUG ((DEBUG_INFO
, "INFO: NodeIndexer = %p\n", NodeIndexer
));
1633 Generator
->IortNodeCount
= IortNodeCount
;
1634 Generator
->NodeIndexer
= NodeIndexer
;
1636 // Calculate the size of the IORT table
1637 TableSize
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE
);
1640 if (ItsGroupNodeCount
> 0) {
1641 ItsGroupOffset
= TableSize
;
1642 // Size of ITS Group node list.
1643 TableSize
+= GetSizeofItsGroupNodes (
1651 // Named Component Nodes
1652 if (NamedComponentNodeCount
> 0) {
1653 NamedComponentOffset
= TableSize
;
1654 // Size of Named Component node list.
1655 TableSize
+= GetSizeofNamedComponentNodes (
1656 NamedComponentOffset
,
1657 NamedComponentNodeList
,
1658 NamedComponentNodeCount
,
1663 // Root Complex Nodes
1664 if (RootComplexNodeCount
> 0) {
1665 RootComplexOffset
= TableSize
;
1666 // Size of Root Complex node list.
1667 TableSize
+= GetSizeofRootComplexNodes (
1669 RootComplexNodeList
,
1670 RootComplexNodeCount
,
1675 // SMMUv1/SMMUv2 Nodes
1676 if (SmmuV1V2NodeCount
> 0) {
1677 SmmuV1V2Offset
= TableSize
;
1678 // Size of SMMUv1/SMMUv2 node list.
1679 TableSize
+= GetSizeofSmmuV1V2Nodes (
1688 if (SmmuV3NodeCount
> 0) {
1689 SmmuV3Offset
= TableSize
;
1690 // Size of SMMUv3 node list.
1691 TableSize
+= GetSizeofSmmuV3Nodes (
1700 if (PmcgNodeCount
> 0) {
1701 PmcgOffset
= TableSize
;
1702 // Size of PMCG node list.
1703 TableSize
+= GetSizeofPmcgNodes (
1714 " IortNodeCount = %d\n" \
1715 " TableSize = %d\n",
1722 " ItsGroupNodeCount = %d\n" \
1723 " ItsGroupOffset = %d\n",
1730 " NamedComponentNodeCount = %d\n" \
1731 " NamedComponentOffset = %d\n",
1732 NamedComponentNodeCount
,
1733 NamedComponentOffset
1738 " RootComplexNodeCount = %d\n" \
1739 " RootComplexOffset = %d\n",
1740 RootComplexNodeCount
,
1746 " SmmuV1V2NodeCount = %d\n" \
1747 " SmmuV1V2Offset = %d\n",
1754 " SmmuV3NodeCount = %d\n" \
1755 " SmmuV3Offset = %d\n",
1762 " PmcgNodeCount = %d\n" \
1763 " PmcgOffset = %d\n",
1768 // Allocate the Buffer for IORT table
1769 *Table
= (EFI_ACPI_DESCRIPTION_HEADER
*)AllocateZeroPool (TableSize
);
1770 if (*Table
== NULL
) {
1771 Status
= EFI_OUT_OF_RESOURCES
;
1774 "ERROR: IORT: Failed to allocate memory for IORT Table, Size = %d," \
1782 Iort
= (EFI_ACPI_6_0_IO_REMAPPING_TABLE
*)*Table
;
1786 "IORT: Iort = 0x%p TableSize = 0x%x\n",
1791 Status
= AddAcpiHeader (
1798 if (EFI_ERROR (Status
)) {
1801 "ERROR: IORT: Failed to add ACPI header. Status = %r\n",
1807 // Update IORT table
1808 Iort
->NumNodes
= IortNodeCount
;
1809 Iort
->NodeOffset
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE
);
1810 Iort
->Reserved
= EFI_ACPI_RESERVED_DWORD
;
1812 if (ItsGroupNodeCount
> 0) {
1813 Status
= AddItsGroupNodes (
1821 if (EFI_ERROR (Status
)) {
1824 "ERROR: IORT: Failed to add ITS Group Node. Status = %r\n",
1831 if (NamedComponentNodeCount
> 0) {
1832 Status
= AddNamedComponentNodes (
1836 NamedComponentOffset
,
1837 NamedComponentNodeList
,
1838 NamedComponentNodeCount
1840 if (EFI_ERROR (Status
)) {
1843 "ERROR: IORT: Failed to add Named Component Node. Status = %r\n",
1850 if (RootComplexNodeCount
> 0) {
1851 Status
= AddRootComplexNodes (
1856 RootComplexNodeList
,
1857 RootComplexNodeCount
1859 if (EFI_ERROR (Status
)) {
1862 "ERROR: IORT: Failed to add Root Complex Node. Status = %r\n",
1869 if (SmmuV1V2NodeCount
> 0) {
1870 Status
= AddSmmuV1V2Nodes (
1878 if (EFI_ERROR (Status
)) {
1881 "ERROR: IORT: Failed to add SMMU v1/v2 Node. Status = %r\n",
1888 if (SmmuV3NodeCount
> 0) {
1889 Status
= AddSmmuV3Nodes (
1897 if (EFI_ERROR (Status
)) {
1900 "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
1907 if (PmcgNodeCount
> 0) {
1908 Status
= AddPmcgNodes (
1916 if (EFI_ERROR (Status
)) {
1919 "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
1929 if (Generator
->NodeIndexer
!= NULL
) {
1930 FreePool (Generator
->NodeIndexer
);
1931 Generator
->NodeIndexer
= NULL
;
1934 if (*Table
!= NULL
) {
1941 /** Free any resources allocated for constructing the IORT
1943 @param [in] This Pointer to the table generator.
1944 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1945 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1947 @param [in, out] Table Pointer to the ACPI Table.
1949 @retval EFI_SUCCESS The resources were freed successfully.
1950 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1954 FreeIortTableResources (
1955 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1956 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
1957 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1958 IN OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
1961 ACPI_IORT_GENERATOR
* Generator
;
1962 ASSERT (This
!= NULL
);
1963 ASSERT (AcpiTableInfo
!= NULL
);
1964 ASSERT (CfgMgrProtocol
!= NULL
);
1965 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
1966 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
1968 Generator
= (ACPI_IORT_GENERATOR
*)This
;
1970 // Free any memory allocated by the generator
1971 if (Generator
->NodeIndexer
!= NULL
) {
1972 FreePool (Generator
->NodeIndexer
);
1973 Generator
->NodeIndexer
= NULL
;
1976 if ((Table
== NULL
) || (*Table
== NULL
)) {
1977 DEBUG ((DEBUG_ERROR
, "ERROR: IORT: Invalid Table Pointer\n"));
1978 ASSERT ((Table
!= NULL
) && (*Table
!= NULL
));
1979 return EFI_INVALID_PARAMETER
;
1987 /** The IORT Table Generator revision.
1989 #define IORT_GENERATOR_REVISION CREATE_REVISION (1, 0)
1991 /** The interface for the MADT Table Generator.
1994 ACPI_IORT_GENERATOR IortGenerator
= {
1995 // ACPI table generator header
1998 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdIort
),
1999 // Generator Description
2000 L
"ACPI.STD.IORT.GENERATOR",
2001 // ACPI Table Signature
2002 EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE
,
2003 // ACPI Table Revision supported by this Generator
2004 EFI_ACPI_IO_REMAPPING_TABLE_REVISION
,
2005 // Minimum supported ACPI Table Revision
2006 EFI_ACPI_IO_REMAPPING_TABLE_REVISION
,
2008 TABLE_GENERATOR_CREATOR_ID_ARM
,
2010 IORT_GENERATOR_REVISION
,
2011 // Build Table function
2013 // Free Resource function
2014 FreeIortTableResources
,
2015 // Extended build function not needed
2017 // Extended build function not implemented by the generator.
2018 // Hence extended free resource function is not required.
2022 // IORT Generator private data
2026 // Pointer to Iort node indexer
2030 /** Register the Generator with the ACPI Table Factory.
2032 @param [in] ImageHandle The handle to the image.
2033 @param [in] SystemTable Pointer to the System Table.
2035 @retval EFI_SUCCESS The Generator is registered.
2036 @retval EFI_INVALID_PARAMETER A parameter is invalid.
2037 @retval EFI_ALREADY_STARTED The Generator for the Table ID
2038 is already registered.
2042 AcpiIortLibConstructor (
2043 IN CONST EFI_HANDLE ImageHandle
,
2044 IN EFI_SYSTEM_TABLE
* CONST SystemTable
2048 Status
= RegisterAcpiTableGenerator (&IortGenerator
.Header
);
2049 DEBUG ((DEBUG_INFO
, "IORT: Register Generator. Status = %r\n", Status
));
2050 ASSERT_EFI_ERROR (Status
);
2054 /** Deregister the Generator from the ACPI Table Factory.
2056 @param [in] ImageHandle The handle to the image.
2057 @param [in] SystemTable Pointer to the System Table.
2059 @retval EFI_SUCCESS The Generator is deregistered.
2060 @retval EFI_INVALID_PARAMETER A parameter is invalid.
2061 @retval EFI_NOT_FOUND The Generator is not registered.
2065 AcpiIortLibDestructor (
2066 IN CONST EFI_HANDLE ImageHandle
,
2067 IN EFI_SYSTEM_TABLE
* CONST SystemTable
2071 Status
= DeregisterAcpiTableGenerator (&IortGenerator
.Header
);
2072 DEBUG ((DEBUG_INFO
, "Iort: Deregister Generator. Status = %r\n", Status
));
2073 ASSERT_EFI_ERROR (Status
);