4 Copyright (c) 2017 - 2022, Arm Limited. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
8 - IO Remapping Table, Platform Design Document, Revision E.d, Feb 2022
9 (https://developer.arm.com/documentation/den0049/)
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
41 - EArmObjGicItsIdentifierArray
42 - EArmObjIdMappingArray
43 - EArmObjSmmuInterruptArray
44 - EArmObjMemoryRangeDescriptor
47 /** This macro expands to a function that retrieves the ITS
48 Group node information from the Configuration Manager.
56 /** This macro expands to a function that retrieves the
57 Named Component node information from the Configuration Manager.
61 EArmObjNamedComponent
,
62 CM_ARM_NAMED_COMPONENT_NODE
65 /** This macro expands to a function that retrieves the
66 Root Complex node information from the Configuration Manager.
71 CM_ARM_ROOT_COMPLEX_NODE
74 /** This macro expands to a function that retrieves the
75 SMMU v1/v2 node information from the Configuration Manager.
80 CM_ARM_SMMUV1_SMMUV2_NODE
83 /** This macro expands to a function that retrieves the
84 SMMU v3 node information from the Configuration Manager.
92 /** This macro expands to a function that retrieves the
93 PMCG node information from the Configuration Manager.
101 /** This macro expands to a function that retrieves the
102 RMR node information from the Configuration Manager.
110 /** This macro expands to a function that retrieves the
111 Memory Range Descriptor Array information from the Configuration Manager.
115 EArmObjMemoryRangeDescriptor
,
116 CM_ARM_MEMORY_RANGE_DESCRIPTOR
119 /** This macro expands to a function that retrieves the
120 ITS Identifier Array information from the Configuration Manager.
124 EArmObjGicItsIdentifierArray
,
125 CM_ARM_ITS_IDENTIFIER
128 /** This macro expands to a function that retrieves the
129 Id Mapping Array information from the Configuration Manager.
133 EArmObjIdMappingArray
,
137 /** This macro expands to a function that retrieves the
138 SMMU Interrupt Array information from the Configuration Manager.
142 EArmObjSmmuInterruptArray
,
143 CM_ARM_SMMU_INTERRUPT
146 /** Returns the size of the ITS Group node.
148 @param [in] Node Pointer to ITS Group node.
150 @retval Size of the ITS Group Node.
154 GetItsGroupNodeSize (
155 IN CONST CM_ARM_ITS_GROUP_NODE
*Node
158 ASSERT (Node
!= NULL
);
160 /* Size of ITS Group Node +
161 Size of ITS Identifier array
163 return (UINT32
)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
) +
164 (Node
->ItsIdCount
* sizeof (UINT32
)));
167 /** Returns the total size required for the ITS Group nodes and
168 updates the Node Indexer.
170 This function calculates the size required for the node group
171 and also populates the Node Indexer array with offsets for the
174 @param [in] NodeStartOffset Offset from the start of the
175 IORT where this node group starts.
176 @param [in] NodeList Pointer to ITS Group node list.
177 @param [in] NodeCount Count of the ITS Group nodes.
178 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
180 @retval Total size of the ITS Group Nodes.
184 GetSizeofItsGroupNodes (
185 IN CONST UINT32 NodeStartOffset
,
186 IN CONST CM_ARM_ITS_GROUP_NODE
*NodeList
,
188 IN OUT IORT_NODE_INDEXER
**CONST NodeIndexer
193 ASSERT (NodeList
!= NULL
);
196 while (NodeCount
-- != 0) {
197 (*NodeIndexer
)->Token
= NodeList
->Token
;
198 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
199 (*NodeIndexer
)->Offset
= (UINT32
)(Size
+ NodeStartOffset
);
200 (*NodeIndexer
)->Identifier
= NodeList
->Identifier
;
203 "IORT: Node Indexer = %p, Token = %p, Object = %p,"
204 " Offset = 0x%x, Identifier = 0x%x\n",
206 (*NodeIndexer
)->Token
,
207 (*NodeIndexer
)->Object
,
208 (*NodeIndexer
)->Offset
,
209 (*NodeIndexer
)->Identifier
212 Size
+= GetItsGroupNodeSize (NodeList
);
220 /** Returns the size of the Named Component node.
222 @param [in] Node Pointer to Named Component node.
224 @retval Size of the Named Component node.
228 GetNamedComponentNodeSize (
229 IN CONST CM_ARM_NAMED_COMPONENT_NODE
*Node
232 ASSERT (Node
!= NULL
);
234 /* Size of Named Component node +
235 Size of ID mapping array +
236 Size of ASCII string + 'padding to 32-bit word aligned'.
238 return (UINT32
)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
) +
239 (Node
->IdMappingCount
*
240 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
)) +
241 ALIGN_VALUE (AsciiStrSize (Node
->ObjectName
), 4));
244 /** Returns the total size required for the Named Component nodes and
245 updates the Node Indexer.
247 This function calculates the size required for the node group
248 and also populates the Node Indexer array with offsets for the
251 @param [in] NodeStartOffset Offset from the start of the
252 IORT where this node group starts.
253 @param [in] NodeList Pointer to Named Component node list.
254 @param [in] NodeCount Count of the Named Component nodes.
255 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
257 @retval Total size of the Named Component nodes.
261 GetSizeofNamedComponentNodes (
262 IN CONST UINT32 NodeStartOffset
,
263 IN CONST CM_ARM_NAMED_COMPONENT_NODE
*NodeList
,
265 IN OUT IORT_NODE_INDEXER
**CONST NodeIndexer
270 ASSERT (NodeList
!= NULL
);
273 while (NodeCount
-- != 0) {
274 (*NodeIndexer
)->Token
= NodeList
->Token
;
275 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
276 (*NodeIndexer
)->Offset
= (UINT32
)(Size
+ NodeStartOffset
);
277 (*NodeIndexer
)->Identifier
= NodeList
->Identifier
;
280 "IORT: Node Indexer = %p, Token = %p, Object = %p,"
281 " Offset = 0x%x, Identifier = 0x%x\n",
283 (*NodeIndexer
)->Token
,
284 (*NodeIndexer
)->Object
,
285 (*NodeIndexer
)->Offset
,
286 (*NodeIndexer
)->Identifier
289 Size
+= GetNamedComponentNodeSize (NodeList
);
297 /** Returns the size of the Root Complex node.
299 @param [in] Node Pointer to Root Complex node.
301 @retval Size of the Root Complex node.
305 GetRootComplexNodeSize (
306 IN CONST CM_ARM_ROOT_COMPLEX_NODE
*Node
309 ASSERT (Node
!= NULL
);
311 /* Size of Root Complex node +
312 Size of ID mapping array
314 return (UINT32
)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
) +
315 (Node
->IdMappingCount
*
316 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
)));
319 /** Returns the total size required for the Root Complex nodes and
320 updates the Node Indexer.
322 This function calculates the size required for the node group
323 and also populates the Node Indexer array with offsets for the
326 @param [in] NodeStartOffset Offset from the start of the
327 IORT where this node group starts.
328 @param [in] NodeList Pointer to Root Complex node list.
329 @param [in] NodeCount Count of the Root Complex nodes.
330 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
332 @retval Total size of the Root Complex nodes.
336 GetSizeofRootComplexNodes (
337 IN CONST UINT32 NodeStartOffset
,
338 IN CONST CM_ARM_ROOT_COMPLEX_NODE
*NodeList
,
340 IN OUT IORT_NODE_INDEXER
**CONST NodeIndexer
345 ASSERT (NodeList
!= NULL
);
348 while (NodeCount
-- != 0) {
349 (*NodeIndexer
)->Token
= NodeList
->Token
;
350 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
351 (*NodeIndexer
)->Offset
= (UINT32
)(Size
+ NodeStartOffset
);
352 (*NodeIndexer
)->Identifier
= NodeList
->Identifier
;
355 "IORT: Node Indexer = %p, Token = %p, Object = %p,"
356 " Offset = 0x%x, Identifier = 0x%x\n",
358 (*NodeIndexer
)->Token
,
359 (*NodeIndexer
)->Object
,
360 (*NodeIndexer
)->Offset
,
361 (*NodeIndexer
)->Identifier
364 Size
+= GetRootComplexNodeSize (NodeList
);
372 /** Returns the size of the SMMUv1/SMMUv2 node.
374 @param [in] Node Pointer to SMMUv1/SMMUv2 node list.
376 @retval Size of the SMMUv1/SMMUv2 node.
380 GetSmmuV1V2NodeSize (
381 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE
*Node
384 ASSERT (Node
!= NULL
);
386 /* Size of SMMU v1/SMMU v2 node +
387 Size of ID mapping array +
388 Size of context interrupt array +
389 Size of PMU interrupt array
391 return (UINT32
)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
) +
392 (Node
->IdMappingCount
*
393 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
)) +
394 (Node
->ContextInterruptCount
*
395 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
)) +
396 (Node
->PmuInterruptCount
*
397 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
)));
400 /** Returns the total size required for the SMMUv1/SMMUv2 nodes and
401 updates the Node Indexer.
403 This function calculates the size required for the node group
404 and also populates the Node Indexer array with offsets for the
407 @param [in] NodeStartOffset Offset from the start of the
408 IORT where this node group starts.
409 @param [in] NodeList Pointer to SMMUv1/SMMUv2 node list.
410 @param [in] NodeCount Count of the SMMUv1/SMMUv2 nodes.
411 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
413 @retval Total size of the SMMUv1/SMMUv2 nodes.
417 GetSizeofSmmuV1V2Nodes (
418 IN CONST UINT32 NodeStartOffset
,
419 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE
*NodeList
,
421 IN OUT IORT_NODE_INDEXER
**CONST NodeIndexer
426 ASSERT (NodeList
!= NULL
);
429 while (NodeCount
-- != 0) {
430 (*NodeIndexer
)->Token
= NodeList
->Token
;
431 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
432 (*NodeIndexer
)->Offset
= (UINT32
)(Size
+ NodeStartOffset
);
433 (*NodeIndexer
)->Identifier
= NodeList
->Identifier
;
436 "IORT: Node Indexer = %p, Token = %p, Object = %p,"
437 " Offset = 0x%x, Identifier = 0x%x\n",
439 (*NodeIndexer
)->Token
,
440 (*NodeIndexer
)->Object
,
441 (*NodeIndexer
)->Offset
,
442 (*NodeIndexer
)->Identifier
445 Size
+= GetSmmuV1V2NodeSize (NodeList
);
453 /** Returns the size of the SMMUv3 node.
455 @param [in] Node Pointer to SMMUv3 node list.
457 @retval Total size of the SMMUv3 nodes.
462 IN CONST CM_ARM_SMMUV3_NODE
*Node
465 ASSERT (Node
!= NULL
);
467 /* Size of SMMU v1/SMMU v2 node +
468 Size of ID mapping array
470 return (UINT32
)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
) +
471 (Node
->IdMappingCount
*
472 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
)));
475 /** Returns the total size required for the SMMUv3 nodes and
476 updates the Node Indexer.
478 This function calculates the size required for the node group
479 and also populates the Node Indexer array with offsets for the
482 @param [in] NodeStartOffset Offset from the start of the
483 IORT where this node group starts.
484 @param [in] NodeList Pointer to SMMUv3 node list.
485 @param [in] NodeCount Count of the SMMUv3 nodes.
486 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
488 @retval Total size of the SMMUv3 nodes.
492 GetSizeofSmmuV3Nodes (
493 IN CONST UINT32 NodeStartOffset
,
494 IN CONST CM_ARM_SMMUV3_NODE
*NodeList
,
496 IN OUT IORT_NODE_INDEXER
**CONST NodeIndexer
501 ASSERT (NodeList
!= NULL
);
504 while (NodeCount
-- != 0) {
505 (*NodeIndexer
)->Token
= NodeList
->Token
;
506 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
507 (*NodeIndexer
)->Offset
= (UINT32
)(Size
+ NodeStartOffset
);
508 (*NodeIndexer
)->Identifier
= NodeList
->Identifier
;
511 "IORT: Node Indexer = %p, Token = %p, Object = %p,"
512 " Offset = 0x%x, Identifier = 0x%x\n",
514 (*NodeIndexer
)->Token
,
515 (*NodeIndexer
)->Object
,
516 (*NodeIndexer
)->Offset
,
517 (*NodeIndexer
)->Identifier
520 Size
+= GetSmmuV3NodeSize (NodeList
);
528 /** Returns the size of the PMCG node.
530 @param [in] Node Pointer to PMCG node.
532 @retval Size of the PMCG node.
537 IN CONST CM_ARM_PMCG_NODE
*Node
540 ASSERT (Node
!= NULL
);
542 /* Size of PMCG node +
543 Size of ID mapping array
545 return (UINT32
)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
) +
546 (Node
->IdMappingCount
*
547 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
)));
550 /** Returns the total size required for the PMCG nodes and
551 updates the Node Indexer.
553 This function calculates the size required for the node group
554 and also populates the Node Indexer array with offsets for the
557 @param [in] NodeStartOffset Offset from the start of the
558 IORT where this node group starts.
559 @param [in] NodeList Pointer to PMCG node list.
560 @param [in] NodeCount Count of the PMCG nodes.
561 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
563 @retval Total size of the PMCG nodes.
568 IN CONST UINT32 NodeStartOffset
,
569 IN CONST CM_ARM_PMCG_NODE
*NodeList
,
571 IN OUT IORT_NODE_INDEXER
**CONST NodeIndexer
576 ASSERT (NodeList
!= NULL
);
579 while (NodeCount
-- != 0) {
580 (*NodeIndexer
)->Token
= NodeList
->Token
;
581 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
582 (*NodeIndexer
)->Offset
= (UINT32
)(Size
+ NodeStartOffset
);
583 (*NodeIndexer
)->Identifier
= NodeList
->Identifier
;
586 "IORT: Node Indexer = %p, Token = %p, Object = %p,"
587 " Offset = 0x%x, Identifier = 0x%x\n",
589 (*NodeIndexer
)->Token
,
590 (*NodeIndexer
)->Object
,
591 (*NodeIndexer
)->Offset
,
592 (*NodeIndexer
)->Identifier
595 Size
+= GetPmcgNodeSize (NodeList
);
603 /** Returns the size of the RMR node.
605 @param [in] Node Pointer to RMR node.
607 @retval Size of the RMR node.
612 IN CONST CM_ARM_RMR_NODE
*Node
615 ASSERT (Node
!= NULL
);
617 /* Size of RMR node +
618 Size of ID mapping array +
619 Size of Memory Range Descriptor array
621 return (UINT32
)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE
) +
622 (Node
->IdMappingCount
*
623 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
)) +
624 (Node
->MemRangeDescCount
*
625 sizeof (EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC
)));
628 /** Returns the total size required for the RMR nodes and
629 updates the Node Indexer.
631 This function calculates the size required for the node group
632 and also populates the Node Indexer array with offsets for the
635 @param [in] NodeStartOffset Offset from the start of the
636 IORT where this node group starts.
637 @param [in] NodeList Pointer to RMR node list.
638 @param [in] NodeCount Count of the RMR nodes.
639 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
641 @retval Total size of the RMR nodes.
646 IN CONST UINT32 NodeStartOffset
,
647 IN CONST CM_ARM_RMR_NODE
*NodeList
,
649 IN OUT IORT_NODE_INDEXER
**CONST NodeIndexer
654 ASSERT (NodeList
!= NULL
);
657 while (NodeCount
-- != 0) {
658 (*NodeIndexer
)->Token
= NodeList
->Token
;
659 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
660 (*NodeIndexer
)->Offset
= (UINT32
)(Size
+ NodeStartOffset
);
661 (*NodeIndexer
)->Identifier
= NodeList
->Identifier
;
664 "IORT: Node Indexer = %p, Token = %p, Object = %p,"
665 " Offset = 0x%x, Identifier = 0x%x\n",
667 (*NodeIndexer
)->Token
,
668 (*NodeIndexer
)->Object
,
669 (*NodeIndexer
)->Offset
,
670 (*NodeIndexer
)->Identifier
673 Size
+= GetRmrNodeSize (NodeList
);
681 /** Returns the offset of the Node referenced by the Token.
683 @param [in] NodeIndexer Pointer to node indexer array.
684 @param [in] NodeCount Count of the nodes.
685 @param [in] Token Reference token for the node.
686 @param [out] NodeOffset Offset of the node from the
687 start of the IORT table.
689 @retval EFI_SUCCESS Success.
690 @retval EFI_NOT_FOUND No matching token reference
691 found in node indexer array.
695 GetNodeOffsetReferencedByToken (
696 IN IORT_NODE_INDEXER
*NodeIndexer
,
698 IN CM_OBJECT_TOKEN Token
,
699 OUT UINT32
*NodeOffset
704 "IORT: Node Indexer: Search Token = %p\n",
707 while (NodeCount
-- != 0) {
710 "IORT: Node Indexer: NodeIndexer->Token = %p, Offset = %d\n",
714 if (NodeIndexer
->Token
== Token
) {
715 *NodeOffset
= NodeIndexer
->Offset
;
718 "IORT: Node Indexer: Token = %p, Found\n",
729 "IORT: Node Indexer: Token = %p, Not Found\n",
732 return EFI_NOT_FOUND
;
735 /** Update the Id Mapping Array.
737 This function retrieves the Id Mapping Array object referenced by the
738 IdMappingToken and updates the IdMapArray.
740 @param [in] This Pointer to the table Generator.
741 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
743 @param [in] IdMapArray Pointer to an array of Id Mappings.
744 @param [in] IdCount Number of Id Mappings.
745 @param [in] IdMappingToken Reference Token for retrieving the
746 Id Mapping Array object.
748 @retval EFI_SUCCESS Table generated successfully.
749 @retval EFI_INVALID_PARAMETER A parameter is invalid.
750 @retval EFI_NOT_FOUND The required object was not found.
755 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
756 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
757 IN EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*IdMapArray
,
759 IN CONST CM_OBJECT_TOKEN IdMappingToken
763 CM_ARM_ID_MAPPING
*IdMappings
;
764 UINT32 IdMappingCount
;
765 ACPI_IORT_GENERATOR
*Generator
;
767 ASSERT (IdMapArray
!= NULL
);
769 Generator
= (ACPI_IORT_GENERATOR
*)This
;
771 // Get the Id Mapping Array
772 Status
= GetEArmObjIdMappingArray (
778 if (EFI_ERROR (Status
)) {
781 "ERROR: IORT: Failed to get Id Mapping array. Status = %r\n",
787 if (IdMappingCount
< IdCount
) {
790 "ERROR: IORT: Failed to get the required number of Id Mappings.\n"
792 return EFI_NOT_FOUND
;
795 // Populate the Id Mapping array
796 while (IdCount
-- != 0) {
797 Status
= GetNodeOffsetReferencedByToken (
798 Generator
->NodeIndexer
,
799 Generator
->IortNodeCount
,
800 IdMappings
->OutputReferenceToken
,
801 &IdMapArray
->OutputReference
803 if (EFI_ERROR (Status
)) {
806 "ERROR: IORT: Failed to get Output Reference for ITS Identifier array."
807 "Reference Token = %p"
809 IdMappings
->OutputReferenceToken
,
815 IdMapArray
->InputBase
= IdMappings
->InputBase
;
816 IdMapArray
->NumIds
= IdMappings
->NumIds
;
817 IdMapArray
->OutputBase
= IdMappings
->OutputBase
;
818 IdMapArray
->Flags
= IdMappings
->Flags
;
822 } // Id Mapping array
827 /** Update the ITS Group Node Information.
829 @param [in] This Pointer to the table Generator.
830 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
832 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
833 @param [in] Iort Pointer to IORT table structure.
834 @param [in] NodesStartOffset Offset for the start of the ITS Group
836 @param [in] NodeList Pointer to an array of ITS Group Node
838 @param [in] NodeCount Number of ITS Group Node Objects.
840 @retval EFI_SUCCESS Table generated successfully.
841 @retval EFI_INVALID_PARAMETER A parameter is invalid.
842 @retval EFI_NOT_FOUND The required object was not found.
847 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
848 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
849 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
850 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
*Iort
,
851 IN CONST UINT32 NodesStartOffset
,
852 IN CONST CM_ARM_ITS_GROUP_NODE
*NodeList
,
857 EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
*ItsGroupNode
;
859 CM_ARM_ITS_IDENTIFIER
*ItsIdentifier
;
860 UINT32 ItsIdentifierCount
;
864 ASSERT (Iort
!= NULL
);
866 ItsGroupNode
= (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
*)((UINT8
*)Iort
+
869 while (NodeCount
-- != 0) {
870 NodeLength
= GetItsGroupNodeSize (NodeList
);
871 if (NodeLength
> MAX_UINT16
) {
872 Status
= EFI_INVALID_PARAMETER
;
875 "ERROR: IORT: ITS Id Array Node length 0x%lx > MAX_UINT16."
883 // Populate the node header
884 ItsGroupNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_ITS_GROUP
;
885 ItsGroupNode
->Node
.Length
= (UINT16
)NodeLength
;
886 ItsGroupNode
->Node
.NumIdMappings
= 0;
887 ItsGroupNode
->Node
.IdReference
= 0;
889 if (AcpiTableInfo
->AcpiTableRevision
<
890 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05
)
892 ItsGroupNode
->Node
.Revision
= 0;
893 ItsGroupNode
->Node
.Identifier
= EFI_ACPI_RESERVED_DWORD
;
895 ItsGroupNode
->Node
.Revision
= 1;
896 ItsGroupNode
->Node
.Identifier
= NodeList
->Identifier
;
899 // IORT specific data
900 ItsGroupNode
->NumItsIdentifiers
= NodeList
->ItsIdCount
;
901 ItsIds
= (UINT32
*)((UINT8
*)ItsGroupNode
+
902 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
));
904 Status
= GetEArmObjGicItsIdentifierArray (
906 NodeList
->ItsIdToken
,
910 if (EFI_ERROR (Status
)) {
913 "ERROR: IORT: Failed to get ITS Identifier array. Status = %r\n",
919 if (ItsIdentifierCount
< ItsGroupNode
->NumItsIdentifiers
) {
922 "ERROR: IORT: Failed to get the required number of ITS Identifiers.\n"
924 return EFI_NOT_FOUND
;
927 // Populate the ITS identifier array
928 for (IdIndex
= 0; IdIndex
< ItsGroupNode
->NumItsIdentifiers
; IdIndex
++) {
929 ItsIds
[IdIndex
] = ItsIdentifier
[IdIndex
].ItsId
;
930 } // ITS identifier array
932 // Next IORT Group Node
933 ItsGroupNode
= (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
*)((UINT8
*)ItsGroupNode
+
934 ItsGroupNode
->Node
.Length
);
941 /** Update the Named Component Node Information.
943 This function updates the Named Component node information in the IORT
946 @param [in] This Pointer to the table Generator.
947 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
949 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
950 @param [in] Iort Pointer to IORT table structure.
951 @param [in] NodesStartOffset Offset for the start of the Named
953 @param [in] NodeList Pointer to an array of Named Component
955 @param [in] NodeCount Number of Named Component Node Objects.
957 @retval EFI_SUCCESS Table generated successfully.
958 @retval EFI_INVALID_PARAMETER A parameter is invalid.
959 @retval EFI_NOT_FOUND The required object was not found.
963 AddNamedComponentNodes (
964 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
965 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
966 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
967 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
*Iort
,
968 IN CONST UINT32 NodesStartOffset
,
969 IN CONST CM_ARM_NAMED_COMPONENT_NODE
*NodeList
,
974 EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
*NcNode
;
975 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*IdMapArray
;
977 UINTN ObjectNameLength
;
980 ASSERT (Iort
!= NULL
);
982 NcNode
= (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
*)((UINT8
*)Iort
+
985 while (NodeCount
-- != 0) {
986 NodeLength
= GetNamedComponentNodeSize (NodeList
);
987 if (NodeLength
> MAX_UINT16
) {
988 Status
= EFI_INVALID_PARAMETER
;
991 "ERROR: IORT: Named Component Node length 0x%lx > MAX_UINT16."
999 // Populate the node header
1000 NcNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_NAMED_COMP
;
1001 NcNode
->Node
.Length
= (UINT16
)NodeLength
;
1002 NcNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1004 if (AcpiTableInfo
->AcpiTableRevision
<
1005 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05
)
1007 NcNode
->Node
.Revision
= 2;
1008 NcNode
->Node
.Identifier
= EFI_ACPI_RESERVED_DWORD
;
1010 NcNode
->Node
.Revision
= 4;
1011 NcNode
->Node
.Identifier
= NodeList
->Identifier
;
1014 ObjectNameLength
= AsciiStrLen (NodeList
->ObjectName
) + 1;
1015 NcNode
->Node
.IdReference
= (NodeList
->IdMappingCount
== 0) ?
1016 0 : ((UINT32
)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
) +
1017 (ALIGN_VALUE (ObjectNameLength
, 4))));
1019 // Named Component specific data
1020 NcNode
->Flags
= NodeList
->Flags
;
1021 NcNode
->CacheCoherent
= NodeList
->CacheCoherent
;
1022 NcNode
->AllocationHints
= NodeList
->AllocationHints
;
1023 NcNode
->Reserved
= EFI_ACPI_RESERVED_WORD
;
1024 NcNode
->MemoryAccessFlags
= NodeList
->MemoryAccessFlags
;
1025 NcNode
->AddressSizeLimit
= NodeList
->AddressSizeLimit
;
1027 // Copy the object name
1028 ObjectName
= (CHAR8
*)((UINT8
*)NcNode
+
1029 sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
));
1030 Status
= AsciiStrCpyS (
1033 NodeList
->ObjectName
1035 if (EFI_ERROR (Status
)) {
1038 "ERROR: IORT: Failed to copy Object Name. Status = %r\n",
1044 if (NodeList
->IdMappingCount
> 0) {
1045 if (NodeList
->IdMappingToken
== CM_NULL_TOKEN
) {
1046 Status
= EFI_INVALID_PARAMETER
;
1049 "ERROR: IORT: Invalid Id Mapping token,"
1050 " Token = 0x%x, Status =%r\n",
1051 NodeList
->IdMappingToken
,
1057 // Ids for Named Component
1058 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)NcNode
+
1059 NcNode
->Node
.IdReference
);
1061 Status
= AddIdMappingArray (
1065 NodeList
->IdMappingCount
,
1066 NodeList
->IdMappingToken
1068 if (EFI_ERROR (Status
)) {
1071 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1078 // Next Named Component Node
1079 NcNode
= (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
*)((UINT8
*)NcNode
+
1080 NcNode
->Node
.Length
);
1082 } // Named Component Node
1087 /** Update the Root Complex Node Information.
1089 This function updates the Root Complex node information in the IORT table.
1091 @param [in] This Pointer to the table Generator.
1092 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1094 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
1095 @param [in] Iort Pointer to IORT table structure.
1096 @param [in] NodesStartOffset Offset for the start of the Root Complex
1098 @param [in] NodeList Pointer to an array of Root Complex Node
1100 @param [in] NodeCount Number of Root Complex Node Objects.
1102 @retval EFI_SUCCESS Table generated successfully.
1103 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1104 @retval EFI_NOT_FOUND The required object was not found.
1108 AddRootComplexNodes (
1109 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1110 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1111 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
1112 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
*Iort
,
1113 IN CONST UINT32 NodesStartOffset
,
1114 IN CONST CM_ARM_ROOT_COMPLEX_NODE
*NodeList
,
1119 EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
*RcNode
;
1120 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*IdMapArray
;
1123 ASSERT (Iort
!= NULL
);
1125 RcNode
= (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
*)((UINT8
*)Iort
+
1128 while (NodeCount
-- != 0) {
1129 NodeLength
= GetRootComplexNodeSize (NodeList
);
1130 if (NodeLength
> MAX_UINT16
) {
1131 Status
= EFI_INVALID_PARAMETER
;
1134 "ERROR: IORT: Root Complex Node length 0x%lx > MAX_UINT16."
1142 // Populate the node header
1143 RcNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_ROOT_COMPLEX
;
1144 RcNode
->Node
.Length
= (UINT16
)NodeLength
;
1145 RcNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1146 RcNode
->Node
.IdReference
= (NodeList
->IdMappingCount
== 0) ?
1147 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
);
1149 if (AcpiTableInfo
->AcpiTableRevision
<
1150 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05
)
1152 RcNode
->Node
.Revision
= 1;
1153 RcNode
->Node
.Identifier
= EFI_ACPI_RESERVED_DWORD
;
1154 RcNode
->PasidCapabilities
= EFI_ACPI_RESERVED_WORD
;
1156 RcNode
->Node
.Revision
= 4;
1157 RcNode
->Node
.Identifier
= NodeList
->Identifier
;
1158 RcNode
->PasidCapabilities
= NodeList
->PasidCapabilities
;
1159 RcNode
->Flags
= NodeList
->Flags
;
1162 // Root Complex specific data
1163 RcNode
->CacheCoherent
= NodeList
->CacheCoherent
;
1164 RcNode
->AllocationHints
= NodeList
->AllocationHints
;
1165 RcNode
->Reserved
= EFI_ACPI_RESERVED_WORD
;
1166 RcNode
->MemoryAccessFlags
= NodeList
->MemoryAccessFlags
;
1167 RcNode
->AtsAttribute
= NodeList
->AtsAttribute
;
1168 RcNode
->PciSegmentNumber
= NodeList
->PciSegmentNumber
;
1169 RcNode
->MemoryAddressSize
= NodeList
->MemoryAddressSize
;
1170 RcNode
->Reserved1
[0] = EFI_ACPI_RESERVED_BYTE
;
1172 if (NodeList
->IdMappingCount
> 0) {
1173 if (NodeList
->IdMappingToken
== CM_NULL_TOKEN
) {
1174 Status
= EFI_INVALID_PARAMETER
;
1177 "ERROR: IORT: Invalid Id Mapping token,"
1178 " Token = 0x%x, Status =%r\n",
1179 NodeList
->IdMappingToken
,
1185 // Ids for Root Complex
1186 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)RcNode
+
1187 RcNode
->Node
.IdReference
);
1188 Status
= AddIdMappingArray (
1192 NodeList
->IdMappingCount
,
1193 NodeList
->IdMappingToken
1195 if (EFI_ERROR (Status
)) {
1198 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1205 // Next Root Complex Node
1206 RcNode
= (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
*)((UINT8
*)RcNode
+
1207 RcNode
->Node
.Length
);
1209 } // Root Complex Node
1214 /** Update the SMMU Interrupt Array.
1216 This function retrieves the InterruptArray object referenced by the
1217 InterruptToken and updates the SMMU InterruptArray.
1219 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1221 @param [in, out] InterruptArray Pointer to an array of Interrupts.
1222 @param [in] InterruptCount Number of entries in the InterruptArray.
1223 @param [in] InterruptToken Reference Token for retrieving the SMMU
1224 InterruptArray object.
1226 @retval EFI_SUCCESS Table generated successfully.
1227 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1228 @retval EFI_NOT_FOUND The required object was not found.
1232 AddSmmuInterruptArray (
1233 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1234 IN OUT EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
*InterruptArray
,
1235 IN UINT32 InterruptCount
,
1236 IN CONST CM_OBJECT_TOKEN InterruptToken
1240 CM_ARM_SMMU_INTERRUPT
*SmmuInterrupt
;
1241 UINT32 SmmuInterruptCount
;
1243 ASSERT (InterruptArray
!= NULL
);
1245 // Get the SMMU Interrupt Array
1246 Status
= GetEArmObjSmmuInterruptArray (
1252 if (EFI_ERROR (Status
)) {
1255 "ERROR: IORT: Failed to get SMMU Interrupt array. Status = %r\n",
1261 if (SmmuInterruptCount
< InterruptCount
) {
1264 "ERROR: IORT: Failed to get the required number of SMMU Interrupts.\n"
1266 return EFI_NOT_FOUND
;
1269 // Populate the Id Mapping array
1270 while (InterruptCount
-- != 0) {
1271 InterruptArray
->Interrupt
= SmmuInterrupt
->Interrupt
;
1272 InterruptArray
->InterruptFlags
= SmmuInterrupt
->Flags
;
1275 } // Id Mapping array
1280 /** Update the SMMU v1/v2 Node Information.
1282 @param [in] This Pointer to the table Generator.
1283 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1285 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
1286 @param [in] Iort Pointer to IORT table structure.
1287 @param [in] NodesStartOffset Offset for the start of the SMMU v1/v2
1289 @param [in] NodeList Pointer to an array of SMMU v1/v2 Node
1291 @param [in] NodeCount Number of SMMU v1/v2 Node Objects.
1293 @retval EFI_SUCCESS Table generated successfully.
1294 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1295 @retval EFI_NOT_FOUND The required object was not found.
1300 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1301 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1302 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
1303 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
*Iort
,
1304 IN CONST UINT32 NodesStartOffset
,
1305 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE
*NodeList
,
1310 EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
*SmmuNode
;
1311 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*IdMapArray
;
1313 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
*ContextInterruptArray
;
1314 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
*PmuInterruptArray
;
1318 ASSERT (Iort
!= NULL
);
1320 SmmuNode
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
*)((UINT8
*)Iort
+
1323 while (NodeCount
-- != 0) {
1324 NodeLength
= GetSmmuV1V2NodeSize (NodeList
);
1325 if (NodeLength
> MAX_UINT16
) {
1326 Status
= EFI_INVALID_PARAMETER
;
1329 "ERROR: IORT: SMMU V1/V2 Node length 0x%lx > MAX_UINT16. Status = %r\n",
1336 // Populate the node header
1337 SmmuNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_SMMUv1v2
;
1338 SmmuNode
->Node
.Length
= (UINT16
)NodeLength
;
1339 SmmuNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1340 SmmuNode
->Node
.IdReference
= (NodeList
->IdMappingCount
== 0) ?
1341 0 : (sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
) +
1342 (NodeList
->ContextInterruptCount
*
1343 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
)) +
1344 (NodeList
->PmuInterruptCount
*
1345 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
)));
1347 if (AcpiTableInfo
->AcpiTableRevision
<
1348 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05
)
1350 SmmuNode
->Node
.Revision
= 1;
1351 SmmuNode
->Node
.Identifier
= EFI_ACPI_RESERVED_DWORD
;
1353 SmmuNode
->Node
.Revision
= 3;
1354 SmmuNode
->Node
.Identifier
= NodeList
->Identifier
;
1357 // SMMU v1/v2 specific data
1358 SmmuNode
->Base
= NodeList
->BaseAddress
;
1359 SmmuNode
->Span
= NodeList
->Span
;
1360 SmmuNode
->Model
= NodeList
->Model
;
1361 SmmuNode
->Flags
= NodeList
->Flags
;
1363 // Reference to Global Interrupt Array
1364 SmmuNode
->GlobalInterruptArrayRef
=
1365 OFFSET_OF (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
, SMMU_NSgIrpt
);
1367 Offset
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
);
1368 // Context Interrupt
1369 SmmuNode
->NumContextInterrupts
= NodeList
->ContextInterruptCount
;
1370 if (NodeList
->ContextInterruptCount
!= 0) {
1371 SmmuNode
->ContextInterruptArrayRef
= Offset
;
1372 ContextInterruptArray
=
1373 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
*)((UINT8
*)SmmuNode
+ Offset
);
1374 Offset
+= (NodeList
->ContextInterruptCount
*
1375 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
));
1379 SmmuNode
->NumPmuInterrupts
= NodeList
->PmuInterruptCount
;
1380 if (NodeList
->PmuInterruptCount
!= 0) {
1381 SmmuNode
->PmuInterruptArrayRef
= Offset
;
1383 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
*)((UINT8
*)SmmuNode
+ Offset
);
1386 SmmuNode
->SMMU_NSgIrpt
= NodeList
->SMMU_NSgIrpt
;
1387 SmmuNode
->SMMU_NSgIrptFlags
= NodeList
->SMMU_NSgIrptFlags
;
1388 SmmuNode
->SMMU_NSgCfgIrpt
= NodeList
->SMMU_NSgCfgIrpt
;
1389 SmmuNode
->SMMU_NSgCfgIrptFlags
= NodeList
->SMMU_NSgCfgIrptFlags
;
1391 if (NodeList
->ContextInterruptCount
!= 0) {
1392 if (NodeList
->ContextInterruptToken
== CM_NULL_TOKEN
) {
1393 Status
= EFI_INVALID_PARAMETER
;
1396 "ERROR: IORT: Invalid Context Interrupt token,"
1397 " Token = 0x%x, Status =%r\n",
1398 NodeList
->ContextInterruptToken
,
1404 // Add Context Interrupt Array
1405 Status
= AddSmmuInterruptArray (
1407 ContextInterruptArray
,
1408 SmmuNode
->NumContextInterrupts
,
1409 NodeList
->ContextInterruptToken
1411 if (EFI_ERROR (Status
)) {
1414 "ERROR: IORT: Failed to Context Interrupt Array. Status = %r\n",
1421 // Add PMU Interrupt Array
1422 if (SmmuNode
->NumPmuInterrupts
!= 0) {
1423 if (NodeList
->PmuInterruptToken
== CM_NULL_TOKEN
) {
1424 Status
= EFI_INVALID_PARAMETER
;
1427 "ERROR: IORT: Invalid PMU Interrupt token,"
1428 " Token = 0x%x, Status =%r\n",
1429 NodeList
->PmuInterruptToken
,
1435 Status
= AddSmmuInterruptArray (
1438 SmmuNode
->NumPmuInterrupts
,
1439 NodeList
->PmuInterruptToken
1441 if (EFI_ERROR (Status
)) {
1444 "ERROR: IORT: Failed to PMU Interrupt Array. Status = %r\n",
1451 if (NodeList
->IdMappingCount
> 0) {
1452 if (NodeList
->IdMappingToken
== CM_NULL_TOKEN
) {
1453 Status
= EFI_INVALID_PARAMETER
;
1456 "ERROR: IORT: Invalid Id Mapping token,"
1457 " Token = 0x%x, Status =%r\n",
1458 NodeList
->IdMappingToken
,
1464 // Ids for SMMU v1/v2 Node
1465 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)SmmuNode
+
1466 SmmuNode
->Node
.IdReference
);
1467 Status
= AddIdMappingArray (
1471 NodeList
->IdMappingCount
,
1472 NodeList
->IdMappingToken
1474 if (EFI_ERROR (Status
)) {
1477 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1484 // Next SMMU v1/v2 Node
1485 SmmuNode
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
*)((UINT8
*)SmmuNode
+
1486 SmmuNode
->Node
.Length
);
1488 } // SMMU v1/v2 Node
1493 /** Update the SMMUv3 Node Information.
1495 This function updates the SMMUv3 node information in the IORT table.
1497 @param [in] This Pointer to the table Generator.
1498 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1500 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
1501 @param [in] Iort Pointer to IORT table structure.
1502 @param [in] NodesStartOffset Offset for the start of the SMMUv3 Nodes.
1503 @param [in] NodeList Pointer to an array of SMMUv3 Node Objects.
1504 @param [in] NodeCount Number of SMMUv3 Node Objects.
1506 @retval EFI_SUCCESS Table generated successfully.
1507 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1508 @retval EFI_NOT_FOUND The required object was not found.
1513 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1514 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1515 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
1516 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
*Iort
,
1517 IN CONST UINT32 NodesStartOffset
,
1518 IN CONST CM_ARM_SMMUV3_NODE
*NodeList
,
1523 EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
*SmmuV3Node
;
1524 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*IdMapArray
;
1527 ASSERT (Iort
!= NULL
);
1529 SmmuV3Node
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
*)((UINT8
*)Iort
+
1532 while (NodeCount
-- != 0) {
1533 NodeLength
= GetSmmuV3NodeSize (NodeList
);
1534 if (NodeLength
> MAX_UINT16
) {
1535 Status
= EFI_INVALID_PARAMETER
;
1538 "ERROR: IORT: SMMU V3 Node length 0x%lx > MAX_UINT16. Status = %r\n",
1545 // Populate the node header
1546 SmmuV3Node
->Node
.Type
= EFI_ACPI_IORT_TYPE_SMMUv3
;
1547 SmmuV3Node
->Node
.Length
= (UINT16
)NodeLength
;
1548 SmmuV3Node
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1549 SmmuV3Node
->Node
.IdReference
= (NodeList
->IdMappingCount
== 0) ?
1550 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
);
1552 if (AcpiTableInfo
->AcpiTableRevision
<
1553 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05
)
1555 SmmuV3Node
->Node
.Revision
= 2;
1556 SmmuV3Node
->Node
.Identifier
= EFI_ACPI_RESERVED_DWORD
;
1558 SmmuV3Node
->Node
.Revision
= 4;
1559 SmmuV3Node
->Node
.Identifier
= NodeList
->Identifier
;
1562 // SMMUv3 specific data
1563 SmmuV3Node
->Base
= NodeList
->BaseAddress
;
1564 SmmuV3Node
->Flags
= NodeList
->Flags
;
1565 SmmuV3Node
->Reserved
= EFI_ACPI_RESERVED_WORD
;
1566 SmmuV3Node
->VatosAddress
= NodeList
->VatosAddress
;
1567 SmmuV3Node
->Model
= NodeList
->Model
;
1568 SmmuV3Node
->Event
= NodeList
->EventInterrupt
;
1569 SmmuV3Node
->Pri
= NodeList
->PriInterrupt
;
1570 SmmuV3Node
->Gerr
= NodeList
->GerrInterrupt
;
1571 SmmuV3Node
->Sync
= NodeList
->SyncInterrupt
;
1573 if ((SmmuV3Node
->Flags
& EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN
) != 0) {
1574 // The Proximity Domain Valid flag is set to 1
1575 SmmuV3Node
->ProximityDomain
= NodeList
->ProximityDomain
;
1577 SmmuV3Node
->ProximityDomain
= 0;
1580 if ((SmmuV3Node
->Event
!= 0) && (SmmuV3Node
->Pri
!= 0) &&
1581 (SmmuV3Node
->Gerr
!= 0) && (SmmuV3Node
->Sync
!= 0))
1583 // If all the SMMU control interrupts are GSIV based,
1584 // the DeviceID mapping index field is ignored.
1585 SmmuV3Node
->DeviceIdMappingIndex
= 0;
1587 SmmuV3Node
->DeviceIdMappingIndex
= NodeList
->DeviceIdMappingIndex
;
1590 if (NodeList
->IdMappingCount
> 0) {
1591 if (NodeList
->IdMappingToken
== CM_NULL_TOKEN
) {
1592 Status
= EFI_INVALID_PARAMETER
;
1595 "ERROR: IORT: Invalid Id Mapping token,"
1596 " Token = 0x%x, Status =%r\n",
1597 NodeList
->IdMappingToken
,
1603 // Ids for SMMUv3 node
1604 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)SmmuV3Node
+
1605 SmmuV3Node
->Node
.IdReference
);
1606 Status
= AddIdMappingArray (
1610 NodeList
->IdMappingCount
,
1611 NodeList
->IdMappingToken
1613 if (EFI_ERROR (Status
)) {
1616 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1624 SmmuV3Node
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
*)((UINT8
*)SmmuV3Node
+
1625 SmmuV3Node
->Node
.Length
);
1632 /** Update the PMCG Node Information.
1634 This function updates the PMCG node information in the IORT table.
1636 @param [in] This Pointer to the table Generator.
1637 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1639 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
1640 @param [in] Iort Pointer to IORT table structure.
1641 @param [in] NodesStartOffset Offset for the start of the PMCG Nodes.
1642 @param [in] NodeList Pointer to an array of PMCG Node Objects.
1643 @param [in] NodeCount Number of PMCG Node Objects.
1645 @retval EFI_SUCCESS Table generated successfully.
1646 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1647 @retval EFI_NOT_FOUND The required object was not found.
1652 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1653 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1654 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
1655 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
*Iort
,
1656 IN CONST UINT32 NodesStartOffset
,
1657 IN CONST CM_ARM_PMCG_NODE
*NodeList
,
1662 EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
*PmcgNode
;
1663 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*IdMapArray
;
1664 ACPI_IORT_GENERATOR
*Generator
;
1667 ASSERT (Iort
!= NULL
);
1669 Generator
= (ACPI_IORT_GENERATOR
*)This
;
1670 PmcgNode
= (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
*)((UINT8
*)Iort
+
1673 while (NodeCount
-- != 0) {
1674 NodeLength
= GetPmcgNodeSize (NodeList
);
1675 if (NodeLength
> MAX_UINT16
) {
1676 Status
= EFI_INVALID_PARAMETER
;
1679 "ERROR: IORT: PMCG Node length 0x%lx > MAX_UINT16. Status = %r\n",
1686 // Populate the node header
1687 PmcgNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_PMCG
;
1688 PmcgNode
->Node
.Length
= (UINT16
)NodeLength
;
1689 PmcgNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1690 PmcgNode
->Node
.IdReference
= (NodeList
->IdMappingCount
== 0) ?
1691 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
);
1693 if (AcpiTableInfo
->AcpiTableRevision
<
1694 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05
)
1696 PmcgNode
->Node
.Revision
= 1;
1697 PmcgNode
->Node
.Identifier
= EFI_ACPI_RESERVED_DWORD
;
1699 PmcgNode
->Node
.Revision
= 2;
1700 PmcgNode
->Node
.Identifier
= NodeList
->Identifier
;
1703 // PMCG specific data
1704 PmcgNode
->Base
= NodeList
->BaseAddress
;
1705 PmcgNode
->OverflowInterruptGsiv
= NodeList
->OverflowInterrupt
;
1706 PmcgNode
->Page1Base
= NodeList
->Page1BaseAddress
;
1708 Status
= GetNodeOffsetReferencedByToken (
1709 Generator
->NodeIndexer
,
1710 Generator
->IortNodeCount
,
1711 NodeList
->ReferenceToken
,
1712 &PmcgNode
->NodeReference
1714 if (EFI_ERROR (Status
)) {
1717 "ERROR: IORT: Failed to get Output Reference for PMCG Node."
1718 "Reference Token = %p"
1720 NodeList
->ReferenceToken
,
1726 if (NodeList
->IdMappingCount
> 0) {
1727 if (NodeList
->IdMappingToken
== CM_NULL_TOKEN
) {
1728 Status
= EFI_INVALID_PARAMETER
;
1731 "ERROR: IORT: Invalid Id Mapping token,"
1732 " Token = 0x%x, Status =%r\n",
1733 NodeList
->IdMappingToken
,
1739 // Ids for PMCG node
1740 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)PmcgNode
+
1741 PmcgNode
->Node
.IdReference
);
1743 Status
= AddIdMappingArray (
1747 NodeList
->IdMappingCount
,
1748 NodeList
->IdMappingToken
1750 if (EFI_ERROR (Status
)) {
1753 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1761 PmcgNode
= (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
*)((UINT8
*)PmcgNode
+
1762 PmcgNode
->Node
.Length
);
1769 /** Update the Memory Range Descriptor Array.
1771 This function retrieves the Memory Range Descriptor objects referenced by
1772 MemRangeDescToken and updates the Memory Range Descriptor array.
1774 @param [in] This Pointer to the table Generator.
1775 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1777 @param [in] DescArray Pointer to an array of Memory Range
1779 @param [in] DescCount Number of Id Descriptors.
1780 @param [in] DescToken Reference Token for retrieving the
1781 Memory Range Descriptor Array.
1783 @retval EFI_SUCCESS Table generated successfully.
1784 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1785 @retval EFI_NOT_FOUND The required object was not found.
1789 AddMemRangeDescArray (
1790 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1791 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1792 IN EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC
*DescArray
,
1793 IN UINT32 DescCount
,
1794 IN CONST CM_OBJECT_TOKEN DescToken
1798 CM_ARM_MEMORY_RANGE_DESCRIPTOR
*MemRangeDesc
;
1799 UINT32 MemRangeDescCount
;
1801 ASSERT (DescArray
!= NULL
);
1803 // Get the Id Mapping Array
1804 Status
= GetEArmObjMemoryRangeDescriptor (
1810 if (EFI_ERROR (Status
)) {
1813 "ERROR: IORT: Failed to get Memory Range Descriptor array. Status = %r\n",
1819 if (MemRangeDescCount
< DescCount
) {
1822 "ERROR: IORT: Failed to get the required number of Memory"
1823 " Range Descriptors.\n"
1825 return EFI_NOT_FOUND
;
1828 // Populate the Memory Range Descriptor array
1829 while (DescCount
-- != 0) {
1830 DescArray
->Base
= MemRangeDesc
->BaseAddress
;
1831 DescArray
->Length
= MemRangeDesc
->Length
;
1832 DescArray
->Reserved
= EFI_ACPI_RESERVED_DWORD
;
1841 /** Update the RMR Node Information.
1843 This function updates the RMR node information in the IORT table.
1845 @param [in] This Pointer to the table Generator.
1846 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1848 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
1849 @param [in] Iort Pointer to IORT table structure.
1850 @param [in] NodesStartOffset Offset for the start of the PMCG Nodes.
1851 @param [in] NodeList Pointer to an array of PMCG Node Objects.
1852 @param [in] NodeCount Number of PMCG Node Objects.
1854 @retval EFI_SUCCESS Table generated successfully.
1855 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1856 @retval EFI_NOT_FOUND The required object was not found.
1861 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1862 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1863 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
1864 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
*Iort
,
1865 IN CONST UINT32 NodesStartOffset
,
1866 IN CONST CM_ARM_RMR_NODE
*NodeList
,
1871 EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE
*RmrNode
;
1872 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*IdMapArray
;
1873 EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC
*MemRangeDescArray
;
1876 ASSERT (Iort
!= NULL
);
1878 RmrNode
= (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE
*)((UINT8
*)Iort
+
1881 while (NodeCount
-- != 0) {
1882 NodeLength
= GetRmrNodeSize (NodeList
);
1883 if (NodeLength
> MAX_UINT16
) {
1884 Status
= EFI_INVALID_PARAMETER
;
1887 "ERROR: IORT: RMR Node length 0x%lx > MAX_UINT16. Status = %r\n",
1894 if (NodeList
->MemRangeDescCount
== 0) {
1895 Status
= EFI_INVALID_PARAMETER
;
1898 "ERROR: IORT: Memory Range Desc count = %d. Status = %r\n",
1899 NodeList
->MemRangeDescCount
,
1905 if (NodeList
->MemRangeDescToken
== CM_NULL_TOKEN
) {
1906 Status
= EFI_INVALID_PARAMETER
;
1909 "ERROR: IORT: Invalid Memory Range Descriptor token,"
1910 " Token = 0x%x. Status = %r\n",
1911 NodeList
->MemRangeDescToken
,
1917 // Populate the node header
1918 RmrNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_RMR
;
1919 RmrNode
->Node
.Length
= (UINT16
)NodeLength
;
1920 RmrNode
->Node
.Revision
= 3;
1921 RmrNode
->Node
.Identifier
= NodeList
->Identifier
;
1922 RmrNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1923 RmrNode
->Node
.IdReference
= (NodeList
->IdMappingCount
== 0) ?
1924 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE
);
1926 // RMR specific data
1927 RmrNode
->Flags
= NodeList
->Flags
;
1928 RmrNode
->NumMemRangeDesc
= NodeList
->MemRangeDescCount
;
1929 RmrNode
->MemRangeDescRef
= (NodeList
->MemRangeDescCount
== 0) ?
1930 0 : (sizeof (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE
) +
1931 (NodeList
->IdMappingCount
*
1932 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
)));
1934 if (NodeList
->IdMappingCount
> 0) {
1935 if (NodeList
->IdMappingToken
== CM_NULL_TOKEN
) {
1936 Status
= EFI_INVALID_PARAMETER
;
1939 "ERROR: IORT: Invalid Id Mapping token,"
1940 " Token = 0x%x, Status =%r\n",
1941 NodeList
->IdMappingToken
,
1948 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)RmrNode
+
1949 RmrNode
->Node
.IdReference
);
1951 Status
= AddIdMappingArray (
1955 NodeList
->IdMappingCount
,
1956 NodeList
->IdMappingToken
1958 if (EFI_ERROR (Status
)) {
1961 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1968 // Memory Range Descriptors for RMR node
1969 MemRangeDescArray
= (EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC
*)(
1971 RmrNode
->MemRangeDescRef
1974 Status
= AddMemRangeDescArray (
1978 NodeList
->MemRangeDescCount
,
1979 NodeList
->MemRangeDescToken
1981 if (EFI_ERROR (Status
)) {
1984 "ERROR: IORT: Failed to Memory Range Descriptor Array. Status = %r\n",
1991 RmrNode
= (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE
*)((UINT8
*)RmrNode
+
1992 RmrNode
->Node
.Length
);
1999 /** Validates that the IORT nodes Identifier are unique.
2001 @param [in] NodeIndexer Pointer to the Node Indexer.
2002 @param [in] NodeCount Number of IORT Nodes.
2004 @retval EFI_SUCCESS Success.
2005 @retval EFI_INVALID_PARAMETER Identifier field not unique.
2009 ValidateNodeIdentifiers (
2010 IN CONST IORT_NODE_INDEXER
*CONST NodeIndexer
,
2017 for (IndexI
= 0; IndexI
< NodeCount
; IndexI
++) {
2018 for (IndexJ
= 0; IndexJ
< NodeCount
; IndexJ
++) {
2019 if ((IndexI
!= IndexJ
) &&
2020 (NodeIndexer
[IndexI
].Identifier
== NodeIndexer
[IndexJ
].Identifier
))
2024 "ERROR: IORT: UID %d of Token %p matches with that of Token %p.\n",
2025 NodeIndexer
[IndexI
].Identifier
,
2026 NodeIndexer
[IndexI
].Token
,
2027 NodeIndexer
[IndexJ
].Token
2029 return EFI_INVALID_PARAMETER
;
2037 /** Construct the IORT ACPI table.
2039 This function invokes the Configuration Manager protocol interface
2040 to get the required hardware information for generating the ACPI
2043 If this function allocates any resources then they must be freed
2044 in the FreeXXXXTableResources function.
2046 @param [in] This Pointer to the table generator.
2047 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
2048 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
2050 @param [out] Table Pointer to the constructed ACPI Table.
2052 @retval EFI_SUCCESS Table generated successfully.
2053 @retval EFI_INVALID_PARAMETER A parameter is invalid.
2054 @retval EFI_NOT_FOUND The required object was not found.
2055 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
2056 Manager is less than the Object size for the
2063 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
2064 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
2065 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
2066 OUT EFI_ACPI_DESCRIPTION_HEADER
**CONST Table
2074 UINT32 IortNodeCount
;
2075 UINT32 ItsGroupNodeCount
;
2076 UINT32 NamedComponentNodeCount
;
2077 UINT32 RootComplexNodeCount
;
2078 UINT32 SmmuV1V2NodeCount
;
2079 UINT32 SmmuV3NodeCount
;
2080 UINT32 PmcgNodeCount
;
2081 UINT32 RmrNodeCount
;
2083 UINT32 ItsGroupOffset
;
2084 UINT32 NamedComponentOffset
;
2085 UINT32 RootComplexOffset
;
2086 UINT32 SmmuV1V2Offset
;
2087 UINT32 SmmuV3Offset
;
2091 CM_ARM_ITS_GROUP_NODE
*ItsGroupNodeList
;
2092 CM_ARM_NAMED_COMPONENT_NODE
*NamedComponentNodeList
;
2093 CM_ARM_ROOT_COMPLEX_NODE
*RootComplexNodeList
;
2094 CM_ARM_SMMUV1_SMMUV2_NODE
*SmmuV1V2NodeList
;
2095 CM_ARM_SMMUV3_NODE
*SmmuV3NodeList
;
2096 CM_ARM_PMCG_NODE
*PmcgNodeList
;
2097 CM_ARM_RMR_NODE
*RmrNodeList
;
2099 EFI_ACPI_6_0_IO_REMAPPING_TABLE
*Iort
;
2100 IORT_NODE_INDEXER
*NodeIndexer
;
2101 ACPI_IORT_GENERATOR
*Generator
;
2103 ASSERT (This
!= NULL
);
2104 ASSERT (AcpiTableInfo
!= NULL
);
2105 ASSERT (CfgMgrProtocol
!= NULL
);
2106 ASSERT (Table
!= NULL
);
2107 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
2108 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
2112 if ((AcpiTableInfo
->AcpiTableRevision
< This
->MinAcpiTableRevision
) ||
2113 (AcpiTableInfo
->AcpiTableRevision
> This
->AcpiTableRevision
))
2117 "ERROR: IORT: Requested table revision = %d, is not supported."
2118 "Supported table revision: Minimum = %d, Maximum = %d\n",
2119 AcpiTableInfo
->AcpiTableRevision
,
2120 This
->MinAcpiTableRevision
,
2121 This
->AcpiTableRevision
2123 return EFI_INVALID_PARAMETER
;
2126 if ((AcpiTableInfo
->AcpiTableRevision
> EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00
) &&
2127 (AcpiTableInfo
->AcpiTableRevision
< EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05
))
2131 "ERROR: IORT: Revisions E (1), E.a(2),b(3),c(4) are not supported.\n"
2133 return EFI_INVALID_PARAMETER
;
2136 Generator
= (ACPI_IORT_GENERATOR
*)This
;
2139 // Get the ITS group node info
2140 Status
= GetEArmObjItsGroup (
2146 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
2149 "ERROR: IORT: Failed to get ITS Group Node Info. Status = %r\n",
2155 // Add the ITS group node count
2156 IortNodeCount
= ItsGroupNodeCount
;
2158 // Get the Named component node info
2159 Status
= GetEArmObjNamedComponent (
2162 &NamedComponentNodeList
,
2163 &NamedComponentNodeCount
2165 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
2168 "ERROR: IORT: Failed to get Named Component Node Info. Status = %r\n",
2174 // Add the Named Component group count
2175 IortNodeCount
+= NamedComponentNodeCount
;
2177 // Get the Root complex node info
2178 Status
= GetEArmObjRootComplex (
2181 &RootComplexNodeList
,
2182 &RootComplexNodeCount
2184 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
2187 "ERROR: IORT: Failed to get Root Complex Node Info. Status = %r\n",
2193 // Add the Root Complex node count
2194 IortNodeCount
+= RootComplexNodeCount
;
2196 // Get the SMMU v1/v2 node info
2197 Status
= GetEArmObjSmmuV1SmmuV2 (
2203 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
2206 "ERROR: IORT: Failed to get SMMUv1/SMMUv2 Node Info. Status = %r\n",
2212 // Add the SMMU v1/v2 node count
2213 IortNodeCount
+= SmmuV1V2NodeCount
;
2215 // Get the SMMUv3 node info
2216 Status
= GetEArmObjSmmuV3 (
2222 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
2225 "ERROR: IORT: Failed to get SMMUv3 Node Info. Status = %r\n",
2231 // Add the SMMUv3 node count
2232 IortNodeCount
+= SmmuV3NodeCount
;
2234 // Get the PMCG node info
2235 Status
= GetEArmObjPmcg (
2241 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
2244 "ERROR: IORT: Failed to get PMCG Node Info. Status = %r\n",
2250 // Add the PMCG node count
2251 IortNodeCount
+= PmcgNodeCount
;
2253 if (AcpiTableInfo
->AcpiTableRevision
>=
2254 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05
)
2256 // Get the RMR node info
2257 Status
= GetEArmObjRmr (
2263 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
2266 "ERROR: IORT: Failed to get RMR Node Info. Status = %r\n",
2272 // Add the RMR node count
2273 IortNodeCount
+= RmrNodeCount
;
2276 // Allocate Node Indexer array
2277 NodeIndexer
= (IORT_NODE_INDEXER
*)AllocateZeroPool (
2278 (sizeof (IORT_NODE_INDEXER
) *
2281 if (NodeIndexer
== NULL
) {
2282 Status
= EFI_OUT_OF_RESOURCES
;
2285 "ERROR: IORT: Failed to allocate memory for Node Indexer" \
2292 DEBUG ((DEBUG_INFO
, "INFO: NodeIndexer = %p\n", NodeIndexer
));
2293 Generator
->IortNodeCount
= IortNodeCount
;
2294 Generator
->NodeIndexer
= NodeIndexer
;
2296 // Calculate the size of the IORT table
2297 TableSize
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE
);
2300 if (ItsGroupNodeCount
> 0) {
2301 ItsGroupOffset
= (UINT32
)TableSize
;
2302 // Size of ITS Group node list.
2303 NodeSize
= GetSizeofItsGroupNodes (
2309 if (NodeSize
> MAX_UINT32
) {
2310 Status
= EFI_INVALID_PARAMETER
;
2313 "ERROR: IORT: Invalid Size of Group Nodes. Status = %r\n",
2319 TableSize
+= NodeSize
;
2323 " ItsGroupNodeCount = %d\n" \
2324 " ItsGroupOffset = %d\n",
2330 // Named Component Nodes
2331 if (NamedComponentNodeCount
> 0) {
2332 NamedComponentOffset
= (UINT32
)TableSize
;
2333 // Size of Named Component node list.
2334 NodeSize
= GetSizeofNamedComponentNodes (
2335 NamedComponentOffset
,
2336 NamedComponentNodeList
,
2337 NamedComponentNodeCount
,
2340 if (NodeSize
> MAX_UINT32
) {
2341 Status
= EFI_INVALID_PARAMETER
;
2344 "ERROR: IORT: Invalid Size of Named Component Nodes. Status = %r\n",
2350 TableSize
+= NodeSize
;
2354 " NamedComponentNodeCount = %d\n" \
2355 " NamedComponentOffset = %d\n",
2356 NamedComponentNodeCount
,
2357 NamedComponentOffset
2361 // Root Complex Nodes
2362 if (RootComplexNodeCount
> 0) {
2363 RootComplexOffset
= (UINT32
)TableSize
;
2364 // Size of Root Complex node list.
2365 NodeSize
= GetSizeofRootComplexNodes (
2367 RootComplexNodeList
,
2368 RootComplexNodeCount
,
2371 if (NodeSize
> MAX_UINT32
) {
2372 Status
= EFI_INVALID_PARAMETER
;
2375 "ERROR: IORT: Invalid Size of Root Complex Nodes. Status = %r\n",
2381 TableSize
+= NodeSize
;
2385 " RootComplexNodeCount = %d\n" \
2386 " RootComplexOffset = %d\n",
2387 RootComplexNodeCount
,
2392 // SMMUv1/SMMUv2 Nodes
2393 if (SmmuV1V2NodeCount
> 0) {
2394 SmmuV1V2Offset
= (UINT32
)TableSize
;
2395 // Size of SMMUv1/SMMUv2 node list.
2396 NodeSize
= GetSizeofSmmuV1V2Nodes (
2402 if (NodeSize
> MAX_UINT32
) {
2403 Status
= EFI_INVALID_PARAMETER
;
2406 "ERROR: IORT: Invalid Size of SMMUv1/v2 Nodes. Status = %r\n",
2412 TableSize
+= NodeSize
;
2416 " SmmuV1V2NodeCount = %d\n" \
2417 " SmmuV1V2Offset = %d\n",
2424 if (SmmuV3NodeCount
> 0) {
2425 SmmuV3Offset
= (UINT32
)TableSize
;
2426 // Size of SMMUv3 node list.
2427 NodeSize
= GetSizeofSmmuV3Nodes (
2433 if (NodeSize
> MAX_UINT32
) {
2434 Status
= EFI_INVALID_PARAMETER
;
2437 "ERROR: IORT: Invalid Size of SMMUv3 Nodes. Status = %r\n",
2443 TableSize
+= NodeSize
;
2447 " SmmuV3NodeCount = %d\n" \
2448 " SmmuV3Offset = %d\n",
2455 if (PmcgNodeCount
> 0) {
2456 PmcgOffset
= (UINT32
)TableSize
;
2457 // Size of PMCG node list.
2458 NodeSize
= GetSizeofPmcgNodes (
2464 if (NodeSize
> MAX_UINT32
) {
2465 Status
= EFI_INVALID_PARAMETER
;
2468 "ERROR: IORT: Invalid Size of PMCG Nodes. Status = %r\n",
2474 TableSize
+= NodeSize
;
2478 " PmcgNodeCount = %d\n" \
2479 " PmcgOffset = %d\n",
2486 if ((AcpiTableInfo
->AcpiTableRevision
>=
2487 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05
) &&
2490 RmrOffset
= (UINT32
)TableSize
;
2491 // Size of RMR node list.
2492 NodeSize
= GetSizeofRmrNodes (
2498 if (NodeSize
> MAX_UINT32
) {
2499 Status
= EFI_INVALID_PARAMETER
;
2502 "ERROR: IORT: Invalid Size of RMR Nodes. Status = %r\n",
2508 TableSize
+= NodeSize
;
2512 " RmrNodeCount = %d\n" \
2513 " RmrOffset = %d\n",
2522 " IortNodeCount = %d\n" \
2523 " TableSize = 0x%lx\n",
2528 if (TableSize
> MAX_UINT32
) {
2529 Status
= EFI_INVALID_PARAMETER
;
2532 "ERROR: IORT: IORT Table Size 0x%lx > MAX_UINT32," \
2540 // Validate that the identifiers for the nodes are unique
2541 if (AcpiTableInfo
->AcpiTableRevision
>=
2542 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05
)
2544 Status
= ValidateNodeIdentifiers (Generator
->NodeIndexer
, IortNodeCount
);
2545 if (EFI_ERROR (Status
)) {
2548 "ERROR: IORT: Node Identifier not unique. Status = %r\n",
2555 // Allocate the Buffer for IORT table
2556 *Table
= (EFI_ACPI_DESCRIPTION_HEADER
*)AllocateZeroPool (TableSize
);
2557 if (*Table
== NULL
) {
2558 Status
= EFI_OUT_OF_RESOURCES
;
2561 "ERROR: IORT: Failed to allocate memory for IORT Table, Size = %d," \
2569 Iort
= (EFI_ACPI_6_0_IO_REMAPPING_TABLE
*)*Table
;
2573 "IORT: Iort = 0x%p TableSize = 0x%lx\n",
2578 Status
= AddAcpiHeader (
2585 if (EFI_ERROR (Status
)) {
2588 "ERROR: IORT: Failed to add ACPI header. Status = %r\n",
2594 // Update IORT table
2595 Iort
->NumNodes
= IortNodeCount
;
2596 Iort
->NodeOffset
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE
);
2597 Iort
->Reserved
= EFI_ACPI_RESERVED_DWORD
;
2599 if (ItsGroupNodeCount
> 0) {
2600 Status
= AddItsGroupNodes (
2609 if (EFI_ERROR (Status
)) {
2612 "ERROR: IORT: Failed to add ITS Group Node. Status = %r\n",
2619 if (NamedComponentNodeCount
> 0) {
2620 Status
= AddNamedComponentNodes (
2625 NamedComponentOffset
,
2626 NamedComponentNodeList
,
2627 NamedComponentNodeCount
2629 if (EFI_ERROR (Status
)) {
2632 "ERROR: IORT: Failed to add Named Component Node. Status = %r\n",
2639 if (RootComplexNodeCount
> 0) {
2640 Status
= AddRootComplexNodes (
2646 RootComplexNodeList
,
2647 RootComplexNodeCount
2649 if (EFI_ERROR (Status
)) {
2652 "ERROR: IORT: Failed to add Root Complex Node. Status = %r\n",
2659 if (SmmuV1V2NodeCount
> 0) {
2660 Status
= AddSmmuV1V2Nodes (
2669 if (EFI_ERROR (Status
)) {
2672 "ERROR: IORT: Failed to add SMMU v1/v2 Node. Status = %r\n",
2679 if (SmmuV3NodeCount
> 0) {
2680 Status
= AddSmmuV3Nodes (
2689 if (EFI_ERROR (Status
)) {
2692 "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
2699 if (PmcgNodeCount
> 0) {
2700 Status
= AddPmcgNodes (
2709 if (EFI_ERROR (Status
)) {
2712 "ERROR: IORT: Failed to add PMCG Node. Status = %r\n",
2719 if ((AcpiTableInfo
->AcpiTableRevision
>=
2720 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05
) &&
2723 Status
= AddRmrNodes (
2732 if (EFI_ERROR (Status
)) {
2735 "ERROR: IORT: Failed to add RMR Node. Status = %r\n",
2745 if (Generator
->NodeIndexer
!= NULL
) {
2746 FreePool (Generator
->NodeIndexer
);
2747 Generator
->NodeIndexer
= NULL
;
2750 if (*Table
!= NULL
) {
2758 /** Free any resources allocated for constructing the IORT
2760 @param [in] This Pointer to the table generator.
2761 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
2762 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
2764 @param [in, out] Table Pointer to the ACPI Table.
2766 @retval EFI_SUCCESS The resources were freed successfully.
2767 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
2771 FreeIortTableResources (
2772 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
2773 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
2774 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
2775 IN OUT EFI_ACPI_DESCRIPTION_HEADER
**CONST Table
2778 ACPI_IORT_GENERATOR
*Generator
;
2780 ASSERT (This
!= NULL
);
2781 ASSERT (AcpiTableInfo
!= NULL
);
2782 ASSERT (CfgMgrProtocol
!= NULL
);
2783 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
2784 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
2786 Generator
= (ACPI_IORT_GENERATOR
*)This
;
2788 // Free any memory allocated by the generator
2789 if (Generator
->NodeIndexer
!= NULL
) {
2790 FreePool (Generator
->NodeIndexer
);
2791 Generator
->NodeIndexer
= NULL
;
2794 if ((Table
== NULL
) || (*Table
== NULL
)) {
2795 DEBUG ((DEBUG_ERROR
, "ERROR: IORT: Invalid Table Pointer\n"));
2796 ASSERT ((Table
!= NULL
) && (*Table
!= NULL
));
2797 return EFI_INVALID_PARAMETER
;
2805 /** The IORT Table Generator revision.
2807 #define IORT_GENERATOR_REVISION CREATE_REVISION (1, 0)
2809 /** The interface for the MADT Table Generator.
2812 ACPI_IORT_GENERATOR IortGenerator
= {
2813 // ACPI table generator header
2816 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdIort
),
2817 // Generator Description
2818 L
"ACPI.STD.IORT.GENERATOR",
2819 // ACPI Table Signature
2820 EFI_ACPI_6_4_IO_REMAPPING_TABLE_SIGNATURE
,
2821 // ACPI Table Revision supported by this Generator
2822 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05
,
2823 // Minimum supported ACPI Table Revision
2824 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00
,
2826 TABLE_GENERATOR_CREATOR_ID_ARM
,
2828 IORT_GENERATOR_REVISION
,
2829 // Build Table function
2831 // Free Resource function
2832 FreeIortTableResources
,
2833 // Extended build function not needed
2835 // Extended build function not implemented by the generator.
2836 // Hence extended free resource function is not required.
2840 // IORT Generator private data
2844 // Pointer to Iort node indexer
2848 /** Register the Generator with the ACPI Table Factory.
2850 @param [in] ImageHandle The handle to the image.
2851 @param [in] SystemTable Pointer to the System Table.
2853 @retval EFI_SUCCESS The Generator is registered.
2854 @retval EFI_INVALID_PARAMETER A parameter is invalid.
2855 @retval EFI_ALREADY_STARTED The Generator for the Table ID
2856 is already registered.
2860 AcpiIortLibConstructor (
2861 IN EFI_HANDLE ImageHandle
,
2862 IN EFI_SYSTEM_TABLE
*SystemTable
2867 Status
= RegisterAcpiTableGenerator (&IortGenerator
.Header
);
2868 DEBUG ((DEBUG_INFO
, "IORT: Register Generator. Status = %r\n", Status
));
2869 ASSERT_EFI_ERROR (Status
);
2873 /** Deregister the Generator from the ACPI Table Factory.
2875 @param [in] ImageHandle The handle to the image.
2876 @param [in] SystemTable Pointer to the System Table.
2878 @retval EFI_SUCCESS The Generator is deregistered.
2879 @retval EFI_INVALID_PARAMETER A parameter is invalid.
2880 @retval EFI_NOT_FOUND The Generator is not registered.
2884 AcpiIortLibDestructor (
2885 IN EFI_HANDLE ImageHandle
,
2886 IN EFI_SYSTEM_TABLE
*SystemTable
2891 Status
= DeregisterAcpiTableGenerator (&IortGenerator
.Header
);
2892 DEBUG ((DEBUG_INFO
, "Iort: Deregister Generator. Status = %r\n", Status
));
2893 ASSERT_EFI_ERROR (Status
);