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 (UINT32
)(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
= (UINT32
)(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 (UINT32
)(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
= (UINT32
)(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 (UINT32
)(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
= (UINT32
)(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 (UINT32
)(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
= (UINT32
)(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 (UINT32
)(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
= (UINT32
)(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 (UINT32
)(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
= (UINT32
)(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
;
740 ASSERT (Iort
!= NULL
);
742 ItsGroupNode
= (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
*)((UINT8
*)Iort
+
745 while (NodeCount
-- != 0) {
746 NodeLength
= GetItsGroupNodeSize (NodeList
);
747 if (NodeLength
> MAX_UINT16
) {
748 Status
= EFI_INVALID_PARAMETER
;
751 "ERROR: IORT: ITS Id Array Node length 0x%lx > MAX_UINT16."
759 // Populate the node header
760 ItsGroupNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_ITS_GROUP
;
761 ItsGroupNode
->Node
.Length
= (UINT16
)NodeLength
;
762 ItsGroupNode
->Node
.Revision
= 0;
763 ItsGroupNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
764 ItsGroupNode
->Node
.NumIdMappings
= 0;
765 ItsGroupNode
->Node
.IdReference
= 0;
767 // IORT specific data
768 ItsGroupNode
->NumItsIdentifiers
= NodeList
->ItsIdCount
;
769 ItsIds
= (UINT32
*)((UINT8
*)ItsGroupNode
+
770 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
));
772 Status
= GetEArmObjGicItsIdentifierArray (
774 NodeList
->ItsIdToken
,
778 if (EFI_ERROR (Status
)) {
781 "ERROR: IORT: Failed to get ITS Identifier array. Status = %r\n",
787 if (ItsIdentifierCount
< ItsGroupNode
->NumItsIdentifiers
) {
790 "ERROR: IORT: Failed to get the required number of ITS Identifiers.\n"
792 return EFI_NOT_FOUND
;
795 // Populate the ITS identifier array
796 for (IdIndex
= 0; IdIndex
< ItsGroupNode
->NumItsIdentifiers
; IdIndex
++) {
797 ItsIds
[IdIndex
] = ItsIdentifier
[IdIndex
].ItsId
;
798 } // ITS identifier array
800 // Next IORT Group Node
801 ItsGroupNode
= (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
*)((UINT8
*)ItsGroupNode
+
802 ItsGroupNode
->Node
.Length
);
809 /** Update the Named Component Node Information.
811 This function updates the Named Component node information in the IORT
814 @param [in] This Pointer to the table Generator.
815 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
817 @param [in] Iort Pointer to IORT table structure.
818 @param [in] NodesStartOffset Offset for the start of the Named
820 @param [in] NodeList Pointer to an array of Named Component
822 @param [in] NodeCount Number of Named Component Node Objects.
824 @retval EFI_SUCCESS Table generated successfully.
825 @retval EFI_INVALID_PARAMETER A parameter is invalid.
826 @retval EFI_NOT_FOUND The required object was not found.
830 AddNamedComponentNodes (
831 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
832 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
833 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
834 IN CONST UINT32 NodesStartOffset
,
835 IN CONST CM_ARM_NAMED_COMPONENT_NODE
* NodeList
,
840 EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
* NcNode
;
841 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
843 UINTN ObjectNameLength
;
846 ASSERT (Iort
!= NULL
);
848 NcNode
= (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
*)((UINT8
*)Iort
+
851 while (NodeCount
-- != 0) {
852 NodeLength
= GetNamedComponentNodeSize (NodeList
);
853 if (NodeLength
> MAX_UINT16
) {
854 Status
= EFI_INVALID_PARAMETER
;
857 "ERROR: IORT: Named Component Node length 0x%lx > MAX_UINT16."
865 // Populate the node header
866 NcNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_NAMED_COMP
;
867 NcNode
->Node
.Length
= (UINT16
)NodeLength
;
868 NcNode
->Node
.Revision
= 2;
869 NcNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
870 NcNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
872 ObjectNameLength
= AsciiStrLen (NodeList
->ObjectName
) + 1;
873 NcNode
->Node
.IdReference
=
874 (UINT32
)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
) +
875 (ALIGN_VALUE (ObjectNameLength
, 4)));
877 // Named Component specific data
878 NcNode
->Flags
= NodeList
->Flags
;
879 NcNode
->CacheCoherent
= NodeList
->CacheCoherent
;
880 NcNode
->AllocationHints
= NodeList
->AllocationHints
;
881 NcNode
->Reserved
= EFI_ACPI_RESERVED_WORD
;
882 NcNode
->MemoryAccessFlags
= NodeList
->MemoryAccessFlags
;
883 NcNode
->AddressSizeLimit
= NodeList
->AddressSizeLimit
;
885 // Copy the object name
886 ObjectName
= (CHAR8
*)((UINT8
*)NcNode
+
887 sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
));
888 Status
= AsciiStrCpyS (
893 if (EFI_ERROR (Status
)) {
896 "ERROR: IORT: Failed to copy Object Name. Status = %r\n",
902 if ((NodeList
->IdMappingCount
> 0) &&
903 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
904 // Ids for Named Component
905 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)NcNode
+
906 NcNode
->Node
.IdReference
);
908 Status
= AddIdMappingArray (
912 NodeList
->IdMappingCount
,
913 NodeList
->IdMappingToken
915 if (EFI_ERROR (Status
)) {
918 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
925 // Next Named Component Node
926 NcNode
= (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
*)((UINT8
*)NcNode
+
927 NcNode
->Node
.Length
);
929 } // Named Component Node
934 /** Update the Root Complex Node Information.
936 This function updates the Root Complex node information in the IORT table.
938 @param [in] This Pointer to the table Generator.
939 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
941 @param [in] Iort Pointer to IORT table structure.
942 @param [in] NodesStartOffset Offset for the start of the Root Complex
944 @param [in] NodeList Pointer to an array of Root Complex Node
946 @param [in] NodeCount Number of Root Complex Node Objects.
948 @retval EFI_SUCCESS Table generated successfully.
949 @retval EFI_INVALID_PARAMETER A parameter is invalid.
950 @retval EFI_NOT_FOUND The required object was not found.
954 AddRootComplexNodes (
955 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
956 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
957 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
958 IN CONST UINT32 NodesStartOffset
,
959 IN CONST CM_ARM_ROOT_COMPLEX_NODE
* NodeList
,
964 EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
* RcNode
;
965 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
968 ASSERT (Iort
!= NULL
);
970 RcNode
= (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
*)((UINT8
*)Iort
+
973 while (NodeCount
-- != 0) {
974 NodeLength
= GetRootComplexNodeSize (NodeList
);
975 if (NodeLength
> MAX_UINT16
) {
976 Status
= EFI_INVALID_PARAMETER
;
979 "ERROR: IORT: Root Complex Node length 0x%lx > MAX_UINT16."
987 // Populate the node header
988 RcNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_ROOT_COMPLEX
;
989 RcNode
->Node
.Length
= (UINT16
)NodeLength
;
990 RcNode
->Node
.Revision
= 1;
991 RcNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
992 RcNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
993 RcNode
->Node
.IdReference
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
);
995 // Root Complex specific data
996 RcNode
->CacheCoherent
= NodeList
->CacheCoherent
;
997 RcNode
->AllocationHints
= NodeList
->AllocationHints
;
998 RcNode
->Reserved
= EFI_ACPI_RESERVED_WORD
;
999 RcNode
->MemoryAccessFlags
= NodeList
->MemoryAccessFlags
;
1000 RcNode
->AtsAttribute
= NodeList
->AtsAttribute
;
1001 RcNode
->PciSegmentNumber
= NodeList
->PciSegmentNumber
;
1002 RcNode
->MemoryAddressSize
= NodeList
->MemoryAddressSize
;
1003 RcNode
->Reserved1
[0] = EFI_ACPI_RESERVED_BYTE
;
1004 RcNode
->Reserved1
[1] = EFI_ACPI_RESERVED_BYTE
;
1005 RcNode
->Reserved1
[2] = EFI_ACPI_RESERVED_BYTE
;
1007 if ((NodeList
->IdMappingCount
> 0) &&
1008 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
1009 // Ids for Root Complex
1010 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)RcNode
+
1011 RcNode
->Node
.IdReference
);
1012 Status
= AddIdMappingArray (
1016 NodeList
->IdMappingCount
,
1017 NodeList
->IdMappingToken
1019 if (EFI_ERROR (Status
)) {
1022 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1029 // Next Root Complex Node
1030 RcNode
= (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
*)((UINT8
*)RcNode
+
1031 RcNode
->Node
.Length
);
1033 } // Root Complex Node
1038 /** Update the SMMU Interrupt Array.
1040 This function retrieves the InterruptArray object referenced by the
1041 InterruptToken and updates the SMMU InterruptArray.
1043 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1045 @param [in, out] InterruptArray Pointer to an array of Interrupts.
1046 @param [in] InterruptCount Number of entries in the InterruptArray.
1047 @param [in] InterruptToken Reference Token for retrieving the SMMU
1048 InterruptArray object.
1050 @retval EFI_SUCCESS Table generated successfully.
1051 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1052 @retval EFI_NOT_FOUND The required object was not found.
1056 AddSmmuInterrruptArray (
1057 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1058 IN OUT EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
* InterruptArray
,
1059 IN UINT32 InterruptCount
,
1060 IN CONST CM_OBJECT_TOKEN InterruptToken
1064 CM_ARM_SMMU_INTERRUPT
* SmmuInterrupt
;
1065 UINT32 SmmuInterruptCount
;
1067 ASSERT (InterruptArray
!= NULL
);
1069 // Get the SMMU Interrupt Array
1070 Status
= GetEArmObjSmmuInterruptArray (
1076 if (EFI_ERROR (Status
)) {
1079 "ERROR: IORT: Failed to get SMMU Interrupt array. Status = %r\n",
1085 if (SmmuInterruptCount
< InterruptCount
) {
1088 "ERROR: IORT: Failed to get the required number of SMMU Interrupts.\n"
1090 return EFI_NOT_FOUND
;
1093 // Populate the Id Mapping array
1094 while (InterruptCount
-- != 0) {
1095 InterruptArray
->Interrupt
= SmmuInterrupt
->Interrupt
;
1096 InterruptArray
->InterruptFlags
= SmmuInterrupt
->Flags
;
1099 } // Id Mapping array
1104 /** Update the SMMU v1/v2 Node Information.
1106 @param [in] This Pointer to the table Generator.
1107 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1109 @param [in] Iort Pointer to IORT table structure.
1110 @param [in] NodesStartOffset Offset for the start of the SMMU v1/v2
1112 @param [in] NodeList Pointer to an array of SMMU v1/v2 Node
1114 @param [in] NodeCount Number of SMMU v1/v2 Node Objects.
1116 @retval EFI_SUCCESS Table generated successfully.
1117 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1118 @retval EFI_NOT_FOUND The required object was not found.
1123 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1124 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1125 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
1126 IN CONST UINT32 NodesStartOffset
,
1127 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE
* NodeList
,
1132 EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
* SmmuNode
;
1133 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
1135 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
* ContextInterruptArray
;
1136 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
* PmuInterruptArray
;
1139 ASSERT (Iort
!= NULL
);
1141 SmmuNode
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
*)((UINT8
*)Iort
+
1144 while (NodeCount
-- != 0) {
1145 NodeLength
= GetSmmuV1V2NodeSize (NodeList
);
1146 if (NodeLength
> MAX_UINT16
) {
1147 Status
= EFI_INVALID_PARAMETER
;
1150 "ERROR: IORT: SMMU V1/V2 Node length 0x%lx > MAX_UINT16. Status = %r\n",
1157 // Populate the node header
1158 SmmuNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_SMMUv1v2
;
1159 SmmuNode
->Node
.Length
= (UINT16
)NodeLength
;
1160 SmmuNode
->Node
.Revision
= 0;
1161 SmmuNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
1162 SmmuNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1163 SmmuNode
->Node
.IdReference
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
) +
1164 (NodeList
->ContextInterruptCount
*
1165 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
)) +
1166 (NodeList
->PmuInterruptCount
*
1167 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
));
1169 // SMMU v1/v2 specific data
1170 SmmuNode
->Base
= NodeList
->BaseAddress
;
1171 SmmuNode
->Span
= NodeList
->Span
;
1172 SmmuNode
->Model
= NodeList
->Model
;
1173 SmmuNode
->Flags
= NodeList
->Flags
;
1175 // Reference to Global Interrupt Array
1176 SmmuNode
->GlobalInterruptArrayRef
=
1177 OFFSET_OF (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
, SMMU_NSgIrpt
);
1179 // Context Interrupt
1180 SmmuNode
->NumContextInterrupts
= NodeList
->ContextInterruptCount
;
1181 SmmuNode
->ContextInterruptArrayRef
=
1182 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
);
1183 ContextInterruptArray
=
1184 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
*)((UINT8
*)SmmuNode
+
1185 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
));
1188 SmmuNode
->NumPmuInterrupts
= NodeList
->PmuInterruptCount
;
1189 SmmuNode
->PmuInterruptArrayRef
= SmmuNode
->ContextInterruptArrayRef
+
1190 (NodeList
->ContextInterruptCount
*
1191 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
));
1193 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
*)((UINT8
*)SmmuNode
+
1194 SmmuNode
->PmuInterruptArrayRef
);
1196 SmmuNode
->SMMU_NSgIrpt
= NodeList
->SMMU_NSgIrpt
;
1197 SmmuNode
->SMMU_NSgIrptFlags
= NodeList
->SMMU_NSgIrptFlags
;
1198 SmmuNode
->SMMU_NSgCfgIrpt
= NodeList
->SMMU_NSgCfgIrpt
;
1199 SmmuNode
->SMMU_NSgCfgIrptFlags
= NodeList
->SMMU_NSgCfgIrptFlags
;
1201 // Add Context Interrupt Array
1202 Status
= AddSmmuInterrruptArray (
1204 ContextInterruptArray
,
1205 SmmuNode
->NumContextInterrupts
,
1206 NodeList
->ContextInterruptToken
1208 if (EFI_ERROR (Status
)) {
1211 "ERROR: IORT: Failed to Context Interrupt Array. Status = %r\n",
1217 // Add PMU Interrupt Array
1218 if ((SmmuNode
->NumPmuInterrupts
> 0) &&
1219 (NodeList
->PmuInterruptToken
!= CM_NULL_TOKEN
)) {
1220 Status
= AddSmmuInterrruptArray (
1223 SmmuNode
->NumPmuInterrupts
,
1224 NodeList
->PmuInterruptToken
1226 if (EFI_ERROR (Status
)) {
1229 "ERROR: IORT: Failed to PMU Interrupt Array. Status = %r\n",
1236 if ((NodeList
->IdMappingCount
> 0) &&
1237 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
1238 // Ids for SMMU v1/v2 Node
1239 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)SmmuNode
+
1240 SmmuNode
->Node
.IdReference
);
1241 Status
= AddIdMappingArray (
1245 NodeList
->IdMappingCount
,
1246 NodeList
->IdMappingToken
1248 if (EFI_ERROR (Status
)) {
1251 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1257 // Next SMMU v1/v2 Node
1258 SmmuNode
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
*)((UINT8
*)SmmuNode
+
1259 SmmuNode
->Node
.Length
);
1261 } // SMMU v1/v2 Node
1266 /** Update the SMMUv3 Node Information.
1268 This function updates the SMMUv3 node information in the IORT table.
1270 @param [in] This Pointer to the table Generator.
1271 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1273 @param [in] Iort Pointer to IORT table structure.
1274 @param [in] NodesStartOffset Offset for the start of the SMMUv3 Nodes.
1275 @param [in] NodeList Pointer to an array of SMMUv3 Node Objects.
1276 @param [in] NodeCount Number of SMMUv3 Node Objects.
1278 @retval EFI_SUCCESS Table generated successfully.
1279 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1280 @retval EFI_NOT_FOUND The required object was not found.
1285 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1286 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1287 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
1288 IN CONST UINT32 NodesStartOffset
,
1289 IN CONST CM_ARM_SMMUV3_NODE
* NodeList
,
1294 EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
* SmmuV3Node
;
1295 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
1298 ASSERT (Iort
!= NULL
);
1300 SmmuV3Node
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
*)((UINT8
*)Iort
+
1303 while (NodeCount
-- != 0) {
1304 NodeLength
= GetSmmuV3NodeSize (NodeList
);
1305 if (NodeLength
> MAX_UINT16
) {
1306 Status
= EFI_INVALID_PARAMETER
;
1309 "ERROR: IORT: SMMU V3 Node length 0x%lx > MAX_UINT16. Status = %r\n",
1316 // Populate the node header
1317 SmmuV3Node
->Node
.Type
= EFI_ACPI_IORT_TYPE_SMMUv3
;
1318 SmmuV3Node
->Node
.Length
= (UINT16
)NodeLength
;
1319 SmmuV3Node
->Node
.Revision
= 2;
1320 SmmuV3Node
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
1321 SmmuV3Node
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1322 SmmuV3Node
->Node
.IdReference
=
1323 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
);
1325 // SMMUv3 specific data
1326 SmmuV3Node
->Base
= NodeList
->BaseAddress
;
1327 SmmuV3Node
->Flags
= NodeList
->Flags
;
1328 SmmuV3Node
->Reserved
= EFI_ACPI_RESERVED_WORD
;
1329 SmmuV3Node
->VatosAddress
= NodeList
->VatosAddress
;
1330 SmmuV3Node
->Model
= NodeList
->Model
;
1331 SmmuV3Node
->Event
= NodeList
->EventInterrupt
;
1332 SmmuV3Node
->Pri
= NodeList
->PriInterrupt
;
1333 SmmuV3Node
->Gerr
= NodeList
->GerrInterrupt
;
1334 SmmuV3Node
->Sync
= NodeList
->SyncInterrupt
;
1336 if ((SmmuV3Node
->Flags
& EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN
) != 0) {
1337 // The Proximity Domain Valid flag is set to 1
1338 SmmuV3Node
->ProximityDomain
= NodeList
->ProximityDomain
;
1340 SmmuV3Node
->ProximityDomain
= 0;
1343 if ((SmmuV3Node
->Event
!= 0) && (SmmuV3Node
->Pri
!= 0) &&
1344 (SmmuV3Node
->Gerr
!= 0) && (SmmuV3Node
->Sync
!= 0)) {
1345 // If all the SMMU control interrupts are GSIV based,
1346 // the DeviceID mapping index field is ignored.
1347 SmmuV3Node
->DeviceIdMappingIndex
= 0;
1349 SmmuV3Node
->DeviceIdMappingIndex
= NodeList
->DeviceIdMappingIndex
;
1352 if ((NodeList
->IdMappingCount
> 0) &&
1353 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
1354 // Ids for SMMUv3 node
1355 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)SmmuV3Node
+
1356 SmmuV3Node
->Node
.IdReference
);
1357 Status
= AddIdMappingArray (
1361 NodeList
->IdMappingCount
,
1362 NodeList
->IdMappingToken
1364 if (EFI_ERROR (Status
)) {
1367 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1375 SmmuV3Node
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
*)((UINT8
*)SmmuV3Node
+
1376 SmmuV3Node
->Node
.Length
);
1383 /** Update the PMCG Node Information.
1385 This function updates the PMCG node information in the IORT table.
1387 @param [in] This Pointer to the table Generator.
1388 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1390 @param [in] Iort Pointer to IORT table structure.
1391 @param [in] NodesStartOffset Offset for the start of the PMCG Nodes.
1392 @param [in] NodeList Pointer to an array of PMCG Node Objects.
1393 @param [in] NodeCount Number of PMCG Node Objects.
1395 @retval EFI_SUCCESS Table generated successfully.
1396 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1397 @retval EFI_NOT_FOUND The required object was not found.
1402 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1403 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1404 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
1405 IN CONST UINT32 NodesStartOffset
,
1406 IN CONST CM_ARM_PMCG_NODE
* NodeList
,
1411 EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
* PmcgNode
;
1412 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
1413 ACPI_IORT_GENERATOR
* Generator
;
1416 ASSERT (Iort
!= NULL
);
1418 Generator
= (ACPI_IORT_GENERATOR
*)This
;
1419 PmcgNode
= (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
*)((UINT8
*)Iort
+
1422 while (NodeCount
-- != 0) {
1423 NodeLength
= GetPmcgNodeSize (NodeList
);
1424 if (NodeLength
> MAX_UINT16
) {
1425 Status
= EFI_INVALID_PARAMETER
;
1428 "ERROR: IORT: PMCG Node length 0x%lx > MAX_UINT16. Status = %r\n",
1435 // Populate the node header
1436 PmcgNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_PMCG
;
1437 PmcgNode
->Node
.Length
= (UINT16
)NodeLength
;
1438 PmcgNode
->Node
.Revision
= 1;
1439 PmcgNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
1440 PmcgNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1441 PmcgNode
->Node
.IdReference
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
);
1443 // PMCG specific data
1444 PmcgNode
->Base
= NodeList
->BaseAddress
;
1445 PmcgNode
->OverflowInterruptGsiv
= NodeList
->OverflowInterrupt
;
1446 PmcgNode
->Page1Base
= NodeList
->Page1BaseAddress
;
1448 Status
= GetNodeOffsetReferencedByToken (
1449 Generator
->NodeIndexer
,
1450 Generator
->IortNodeCount
,
1451 NodeList
->ReferenceToken
,
1452 &PmcgNode
->NodeReference
1454 if (EFI_ERROR (Status
)) {
1457 "ERROR: IORT: Failed to get Output Reference for PMCG Node."
1458 "Reference Token = %p"
1460 NodeList
->ReferenceToken
,
1466 if ((NodeList
->IdMappingCount
> 0) &&
1467 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
1468 // Ids for PMCG node
1469 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)PmcgNode
+
1470 PmcgNode
->Node
.IdReference
);
1472 Status
= AddIdMappingArray (
1476 NodeList
->IdMappingCount
,
1477 NodeList
->IdMappingToken
1479 if (EFI_ERROR (Status
)) {
1482 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1490 PmcgNode
= (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
*)((UINT8
*)PmcgNode
+
1491 PmcgNode
->Node
.Length
);
1498 /** Construct the IORT ACPI table.
1500 This function invokes the Configuration Manager protocol interface
1501 to get the required hardware information for generating the ACPI
1504 If this function allocates any resources then they must be freed
1505 in the FreeXXXXTableResources function.
1507 @param [in] This Pointer to the table generator.
1508 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1509 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1511 @param [out] Table Pointer to the constructed ACPI Table.
1513 @retval EFI_SUCCESS Table generated successfully.
1514 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1515 @retval EFI_NOT_FOUND The required object was not found.
1516 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
1517 Manager is less than the Object size for the
1524 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1525 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
1526 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1527 OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
1535 UINT32 IortNodeCount
;
1536 UINT32 ItsGroupNodeCount
;
1537 UINT32 NamedComponentNodeCount
;
1538 UINT32 RootComplexNodeCount
;
1539 UINT32 SmmuV1V2NodeCount
;
1540 UINT32 SmmuV3NodeCount
;
1541 UINT32 PmcgNodeCount
;
1543 UINT32 ItsGroupOffset
;
1544 UINT32 NamedComponentOffset
;
1545 UINT32 RootComplexOffset
;
1546 UINT32 SmmuV1V2Offset
;
1547 UINT32 SmmuV3Offset
;
1550 CM_ARM_ITS_GROUP_NODE
* ItsGroupNodeList
;
1551 CM_ARM_NAMED_COMPONENT_NODE
* NamedComponentNodeList
;
1552 CM_ARM_ROOT_COMPLEX_NODE
* RootComplexNodeList
;
1553 CM_ARM_SMMUV1_SMMUV2_NODE
* SmmuV1V2NodeList
;
1554 CM_ARM_SMMUV3_NODE
* SmmuV3NodeList
;
1555 CM_ARM_PMCG_NODE
* PmcgNodeList
;
1557 EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
;
1558 IORT_NODE_INDEXER
* NodeIndexer
;
1559 ACPI_IORT_GENERATOR
* Generator
;
1561 ASSERT (This
!= NULL
);
1562 ASSERT (AcpiTableInfo
!= NULL
);
1563 ASSERT (CfgMgrProtocol
!= NULL
);
1564 ASSERT (Table
!= NULL
);
1565 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
1566 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
1568 if ((AcpiTableInfo
->AcpiTableRevision
< This
->MinAcpiTableRevision
) ||
1569 (AcpiTableInfo
->AcpiTableRevision
> This
->AcpiTableRevision
)) {
1572 "ERROR: IORT: Requested table revision = %d, is not supported."
1573 "Supported table revision: Minimum = %d, Maximum = %d\n",
1574 AcpiTableInfo
->AcpiTableRevision
,
1575 This
->MinAcpiTableRevision
,
1576 This
->AcpiTableRevision
1578 return EFI_INVALID_PARAMETER
;
1581 Generator
= (ACPI_IORT_GENERATOR
*)This
;
1584 // Get the ITS group node info
1585 Status
= GetEArmObjItsGroup (
1591 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1594 "ERROR: IORT: Failed to get ITS Group Node Info. Status = %r\n",
1600 // Add the ITS group node count
1601 IortNodeCount
= ItsGroupNodeCount
;
1603 // Get the Named component node info
1604 Status
= GetEArmObjNamedComponent (
1607 &NamedComponentNodeList
,
1608 &NamedComponentNodeCount
1610 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1613 "ERROR: IORT: Failed to get Named Component Node Info. Status = %r\n",
1619 // Add the Named Component group count
1620 IortNodeCount
+= NamedComponentNodeCount
;
1622 // Get the Root complex node info
1623 Status
= GetEArmObjRootComplex (
1626 &RootComplexNodeList
,
1627 &RootComplexNodeCount
1629 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1632 "ERROR: IORT: Failed to get Root Complex Node Info. Status = %r\n",
1638 // Add the Root Complex node count
1639 IortNodeCount
+= RootComplexNodeCount
;
1641 // Get the SMMU v1/v2 node info
1642 Status
= GetEArmObjSmmuV1SmmuV2 (
1648 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1651 "ERROR: IORT: Failed to get SMMUv1/SMMUv2 Node Info. Status = %r\n",
1657 // Add the SMMU v1/v2 node count
1658 IortNodeCount
+= SmmuV1V2NodeCount
;
1660 // Get the SMMUv3 node info
1661 Status
= GetEArmObjSmmuV3 (
1667 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1670 "ERROR: IORT: Failed to get SMMUv3 Node Info. Status = %r\n",
1676 // Add the SMMUv3 node count
1677 IortNodeCount
+= SmmuV3NodeCount
;
1679 // Get the PMCG node info
1680 Status
= GetEArmObjPmcg (
1686 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1689 "ERROR: IORT: Failed to get PMCG Node Info. Status = %r\n",
1695 // Add the PMCG node count
1696 IortNodeCount
+= PmcgNodeCount
;
1698 // Allocate Node Indexer array
1699 NodeIndexer
= (IORT_NODE_INDEXER
*)AllocateZeroPool (
1700 (sizeof (IORT_NODE_INDEXER
) *
1703 if (NodeIndexer
== NULL
) {
1704 Status
= EFI_OUT_OF_RESOURCES
;
1707 "ERROR: IORT: Failed to allocate memory for Node Indexer" \
1714 DEBUG ((DEBUG_INFO
, "INFO: NodeIndexer = %p\n", NodeIndexer
));
1715 Generator
->IortNodeCount
= IortNodeCount
;
1716 Generator
->NodeIndexer
= NodeIndexer
;
1718 // Calculate the size of the IORT table
1719 TableSize
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE
);
1722 if (ItsGroupNodeCount
> 0) {
1723 ItsGroupOffset
= (UINT32
)TableSize
;
1724 // Size of ITS Group node list.
1725 NodeSize
= GetSizeofItsGroupNodes (
1731 if (NodeSize
> MAX_UINT32
) {
1732 Status
= EFI_INVALID_PARAMETER
;
1735 "ERROR: IORT: Invalid Size of Group Nodes. Status = %r\n",
1740 TableSize
+= NodeSize
;
1744 " ItsGroupNodeCount = %d\n" \
1745 " ItsGroupOffset = %d\n",
1751 // Named Component Nodes
1752 if (NamedComponentNodeCount
> 0) {
1753 NamedComponentOffset
= (UINT32
)TableSize
;
1754 // Size of Named Component node list.
1755 NodeSize
= GetSizeofNamedComponentNodes (
1756 NamedComponentOffset
,
1757 NamedComponentNodeList
,
1758 NamedComponentNodeCount
,
1761 if (NodeSize
> MAX_UINT32
) {
1762 Status
= EFI_INVALID_PARAMETER
;
1765 "ERROR: IORT: Invalid Size of Named Component Nodes. Status = %r\n",
1770 TableSize
+= NodeSize
;
1774 " NamedComponentNodeCount = %d\n" \
1775 " NamedComponentOffset = %d\n",
1776 NamedComponentNodeCount
,
1777 NamedComponentOffset
1781 // Root Complex Nodes
1782 if (RootComplexNodeCount
> 0) {
1783 RootComplexOffset
= (UINT32
)TableSize
;
1784 // Size of Root Complex node list.
1785 NodeSize
= GetSizeofRootComplexNodes (
1787 RootComplexNodeList
,
1788 RootComplexNodeCount
,
1791 if (NodeSize
> MAX_UINT32
) {
1792 Status
= EFI_INVALID_PARAMETER
;
1795 "ERROR: IORT: Invalid Size of Root Complex Nodes. Status = %r\n",
1800 TableSize
+= NodeSize
;
1804 " RootComplexNodeCount = %d\n" \
1805 " RootComplexOffset = %d\n",
1806 RootComplexNodeCount
,
1811 // SMMUv1/SMMUv2 Nodes
1812 if (SmmuV1V2NodeCount
> 0) {
1813 SmmuV1V2Offset
= (UINT32
)TableSize
;
1814 // Size of SMMUv1/SMMUv2 node list.
1815 NodeSize
= GetSizeofSmmuV1V2Nodes (
1821 if (NodeSize
> MAX_UINT32
) {
1822 Status
= EFI_INVALID_PARAMETER
;
1825 "ERROR: IORT: Invalid Size of SMMUv1/v2 Nodes. Status = %r\n",
1830 TableSize
+= NodeSize
;
1834 " SmmuV1V2NodeCount = %d\n" \
1835 " SmmuV1V2Offset = %d\n",
1842 if (SmmuV3NodeCount
> 0) {
1843 SmmuV3Offset
= (UINT32
)TableSize
;
1844 // Size of SMMUv3 node list.
1845 NodeSize
= GetSizeofSmmuV3Nodes (
1851 if (NodeSize
> MAX_UINT32
) {
1852 Status
= EFI_INVALID_PARAMETER
;
1855 "ERROR: IORT: Invalid Size of SMMUv3 Nodes. Status = %r\n",
1860 TableSize
+= NodeSize
;
1864 " SmmuV3NodeCount = %d\n" \
1865 " SmmuV3Offset = %d\n",
1872 if (PmcgNodeCount
> 0) {
1873 PmcgOffset
= (UINT32
)TableSize
;
1874 // Size of PMCG node list.
1875 NodeSize
= GetSizeofPmcgNodes (
1881 if (NodeSize
> MAX_UINT32
) {
1882 Status
= EFI_INVALID_PARAMETER
;
1885 "ERROR: IORT: Invalid Size of PMCG Nodes. Status = %r\n",
1890 TableSize
+= NodeSize
;
1894 " PmcgNodeCount = %d\n" \
1895 " PmcgOffset = %d\n",
1904 " IortNodeCount = %d\n" \
1905 " TableSize = 0x%lx\n",
1910 if (TableSize
> MAX_UINT32
) {
1911 Status
= EFI_INVALID_PARAMETER
;
1914 "ERROR: IORT: IORT Table Size 0x%lx > MAX_UINT32," \
1922 // Allocate the Buffer for IORT table
1923 *Table
= (EFI_ACPI_DESCRIPTION_HEADER
*)AllocateZeroPool (TableSize
);
1924 if (*Table
== NULL
) {
1925 Status
= EFI_OUT_OF_RESOURCES
;
1928 "ERROR: IORT: Failed to allocate memory for IORT Table, Size = %d," \
1936 Iort
= (EFI_ACPI_6_0_IO_REMAPPING_TABLE
*)*Table
;
1940 "IORT: Iort = 0x%p TableSize = 0x%lx\n",
1945 Status
= AddAcpiHeader (
1952 if (EFI_ERROR (Status
)) {
1955 "ERROR: IORT: Failed to add ACPI header. Status = %r\n",
1961 // Update IORT table
1962 Iort
->NumNodes
= IortNodeCount
;
1963 Iort
->NodeOffset
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE
);
1964 Iort
->Reserved
= EFI_ACPI_RESERVED_DWORD
;
1966 if (ItsGroupNodeCount
> 0) {
1967 Status
= AddItsGroupNodes (
1975 if (EFI_ERROR (Status
)) {
1978 "ERROR: IORT: Failed to add ITS Group Node. Status = %r\n",
1985 if (NamedComponentNodeCount
> 0) {
1986 Status
= AddNamedComponentNodes (
1990 NamedComponentOffset
,
1991 NamedComponentNodeList
,
1992 NamedComponentNodeCount
1994 if (EFI_ERROR (Status
)) {
1997 "ERROR: IORT: Failed to add Named Component Node. Status = %r\n",
2004 if (RootComplexNodeCount
> 0) {
2005 Status
= AddRootComplexNodes (
2010 RootComplexNodeList
,
2011 RootComplexNodeCount
2013 if (EFI_ERROR (Status
)) {
2016 "ERROR: IORT: Failed to add Root Complex Node. Status = %r\n",
2023 if (SmmuV1V2NodeCount
> 0) {
2024 Status
= AddSmmuV1V2Nodes (
2032 if (EFI_ERROR (Status
)) {
2035 "ERROR: IORT: Failed to add SMMU v1/v2 Node. Status = %r\n",
2042 if (SmmuV3NodeCount
> 0) {
2043 Status
= AddSmmuV3Nodes (
2051 if (EFI_ERROR (Status
)) {
2054 "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
2061 if (PmcgNodeCount
> 0) {
2062 Status
= AddPmcgNodes (
2070 if (EFI_ERROR (Status
)) {
2073 "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
2083 if (Generator
->NodeIndexer
!= NULL
) {
2084 FreePool (Generator
->NodeIndexer
);
2085 Generator
->NodeIndexer
= NULL
;
2088 if (*Table
!= NULL
) {
2095 /** Free any resources allocated for constructing the IORT
2097 @param [in] This Pointer to the table generator.
2098 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
2099 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
2101 @param [in, out] Table Pointer to the ACPI Table.
2103 @retval EFI_SUCCESS The resources were freed successfully.
2104 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
2108 FreeIortTableResources (
2109 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
2110 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
2111 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
2112 IN OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
2115 ACPI_IORT_GENERATOR
* Generator
;
2116 ASSERT (This
!= NULL
);
2117 ASSERT (AcpiTableInfo
!= NULL
);
2118 ASSERT (CfgMgrProtocol
!= NULL
);
2119 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
2120 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
2122 Generator
= (ACPI_IORT_GENERATOR
*)This
;
2124 // Free any memory allocated by the generator
2125 if (Generator
->NodeIndexer
!= NULL
) {
2126 FreePool (Generator
->NodeIndexer
);
2127 Generator
->NodeIndexer
= NULL
;
2130 if ((Table
== NULL
) || (*Table
== NULL
)) {
2131 DEBUG ((DEBUG_ERROR
, "ERROR: IORT: Invalid Table Pointer\n"));
2132 ASSERT ((Table
!= NULL
) && (*Table
!= NULL
));
2133 return EFI_INVALID_PARAMETER
;
2141 /** The IORT Table Generator revision.
2143 #define IORT_GENERATOR_REVISION CREATE_REVISION (1, 0)
2145 /** The interface for the MADT Table Generator.
2148 ACPI_IORT_GENERATOR IortGenerator
= {
2149 // ACPI table generator header
2152 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdIort
),
2153 // Generator Description
2154 L
"ACPI.STD.IORT.GENERATOR",
2155 // ACPI Table Signature
2156 EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE
,
2157 // ACPI Table Revision supported by this Generator
2158 EFI_ACPI_IO_REMAPPING_TABLE_REVISION
,
2159 // Minimum supported ACPI Table Revision
2160 EFI_ACPI_IO_REMAPPING_TABLE_REVISION
,
2162 TABLE_GENERATOR_CREATOR_ID_ARM
,
2164 IORT_GENERATOR_REVISION
,
2165 // Build Table function
2167 // Free Resource function
2168 FreeIortTableResources
,
2169 // Extended build function not needed
2171 // Extended build function not implemented by the generator.
2172 // Hence extended free resource function is not required.
2176 // IORT Generator private data
2180 // Pointer to Iort node indexer
2184 /** Register the Generator with the ACPI Table Factory.
2186 @param [in] ImageHandle The handle to the image.
2187 @param [in] SystemTable Pointer to the System Table.
2189 @retval EFI_SUCCESS The Generator is registered.
2190 @retval EFI_INVALID_PARAMETER A parameter is invalid.
2191 @retval EFI_ALREADY_STARTED The Generator for the Table ID
2192 is already registered.
2196 AcpiIortLibConstructor (
2197 IN EFI_HANDLE ImageHandle
,
2198 IN EFI_SYSTEM_TABLE
* SystemTable
2202 Status
= RegisterAcpiTableGenerator (&IortGenerator
.Header
);
2203 DEBUG ((DEBUG_INFO
, "IORT: Register Generator. Status = %r\n", Status
));
2204 ASSERT_EFI_ERROR (Status
);
2208 /** Deregister the Generator from the ACPI Table Factory.
2210 @param [in] ImageHandle The handle to the image.
2211 @param [in] SystemTable Pointer to the System Table.
2213 @retval EFI_SUCCESS The Generator is deregistered.
2214 @retval EFI_INVALID_PARAMETER A parameter is invalid.
2215 @retval EFI_NOT_FOUND The Generator is not registered.
2219 AcpiIortLibDestructor (
2220 IN EFI_HANDLE ImageHandle
,
2221 IN EFI_SYSTEM_TABLE
* SystemTable
2225 Status
= DeregisterAcpiTableGenerator (&IortGenerator
.Header
);
2226 DEBUG ((DEBUG_INFO
, "Iort: Deregister Generator. Status = %r\n", Status
));
2227 ASSERT_EFI_ERROR (Status
);