4 Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 - IO Remapping Table, Platform Design Document,
15 Document number: ARM DEN 0049D, Issue D, March 2018
19 #include <IndustryStandard/IoRemappingTable.h>
20 #include <Library/AcpiLib.h>
21 #include <Library/BaseLib.h>
22 #include <Library/DebugLib.h>
23 #include <Library/MemoryAllocationLib.h>
24 #include <Protocol/AcpiTable.h>
26 // Module specific include files.
27 #include <AcpiTableGenerator.h>
28 #include <ConfigurationManagerObject.h>
29 #include <ConfigurationManagerHelper.h>
30 #include <Library/TableHelperLib.h>
31 #include <Protocol/ConfigurationManagerProtocol.h>
33 #include "IortGenerator.h"
35 /** ARM standard IORT Generator
38 The following Configuration Manager Object(s) are required by
41 - EArmObjNamedComponent
46 - EArmObjGicItsIdentifierArray
48 - EArmObjGicItsIdentifierArray
51 /** This macro expands to a function that retrieves the ITS
52 Group node information from the Configuration Manager.
60 /** This macro expands to a function that retrieves the
61 Named Component node information from the Configuration Manager.
65 EArmObjNamedComponent
,
66 CM_ARM_NAMED_COMPONENT_NODE
69 /** This macro expands to a function that retrieves the
70 Root Complex node information from the Configuration Manager.
75 CM_ARM_ROOT_COMPLEX_NODE
78 /** This macro expands to a function that retrieves the
79 SMMU v1/v2 node information from the Configuration Manager.
84 CM_ARM_SMMUV1_SMMUV2_NODE
87 /** This macro expands to a function that retrieves the
88 SMMU v3 node information from the Configuration Manager.
96 /** This macro expands to a function that retrieves the
97 PMCG node information from the Configuration Manager.
105 /** This macro expands to a function that retrieves the
106 ITS Identifier Array information from the Configuration Manager.
110 EArmObjGicItsIdentifierArray
,
111 CM_ARM_ITS_IDENTIFIER
114 /** This macro expands to a function that retrieves the
115 Id Mapping Array information from the Configuration Manager.
123 /** This macro expands to a function that retrieves the
124 SMMU Interrupt Array information from the Configuration Manager.
128 EArmObjSmmuInterruptArray
,
129 CM_ARM_SMMU_INTERRUPT
132 /** Returns the size of the ITS Group node.
134 @param [in] Node Pointer to ITS Group node.
136 @retval Size of the ITS Group Node.
140 GetItsGroupNodeSize (
141 IN CONST CM_ARM_ITS_GROUP_NODE
* Node
144 ASSERT (Node
!= NULL
);
146 /* Size of ITS Group Node +
147 Size of ITS Identifier array
149 return sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
) +
150 (Node
->ItsIdCount
* sizeof (UINT32
));
153 /** Returns the total size required for the ITS Group nodes and
154 updates the Node Indexer.
156 This function calculates the size required for the node group
157 and also populates the Node Indexer array with offsets for the
160 @param [in] NodeStartOffset Offset from the start of the
161 IORT where this node group starts.
162 @param [in] NodeList Pointer to ITS Group node list.
163 @param [in] NodeCount Count of the ITS Group nodes.
164 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
166 @retval Total size of the ITS Group Nodes.
170 GetSizeofItsGroupNodes (
171 IN CONST UINT32 NodeStartOffset
,
172 IN CONST CM_ARM_ITS_GROUP_NODE
* NodeList
,
174 IN OUT IORT_NODE_INDEXER
** CONST NodeIndexer
179 ASSERT (NodeList
!= NULL
);
182 while (NodeCount
-- != 0) {
183 (*NodeIndexer
)->Token
= NodeList
->Token
;
184 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
185 (*NodeIndexer
)->Offset
= Size
+ NodeStartOffset
;
188 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
190 (*NodeIndexer
)->Token
,
191 (*NodeIndexer
)->Object
,
192 (*NodeIndexer
)->Offset
195 Size
+= GetItsGroupNodeSize (NodeList
);
202 /** Returns the size of the Named Component node.
204 @param [in] Node Pointer to Named Component node.
206 @retval Size of the Named Component node.
210 GetNamedComponentNodeSize (
211 IN CONST CM_ARM_NAMED_COMPONENT_NODE
* Node
214 ASSERT (Node
!= NULL
);
216 /* Size of Named Component node +
217 Size of ID mapping array +
218 Size of ASCII string + 'padding to 32-bit word aligned'.
220 return sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
) +
221 (Node
->IdMappingCount
*
222 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
)) +
223 ALIGN_VALUE (AsciiStrSize (Node
->ObjectName
), 4);
226 /** Returns the total size required for the Named Component nodes and
227 updates the Node Indexer.
229 This function calculates the size required for the node group
230 and also populates the Node Indexer array with offsets for the
233 @param [in] NodeStartOffset Offset from the start of the
234 IORT where this node group starts.
235 @param [in] NodeList Pointer to Named Component node list.
236 @param [in] NodeCount Count of the Named Component nodes.
237 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
239 @retval Total size of the Named Component nodes.
243 GetSizeofNamedComponentNodes (
244 IN CONST UINT32 NodeStartOffset
,
245 IN CONST CM_ARM_NAMED_COMPONENT_NODE
* NodeList
,
247 IN OUT IORT_NODE_INDEXER
** CONST NodeIndexer
252 ASSERT (NodeList
!= NULL
);
255 while (NodeCount
-- != 0) {
256 (*NodeIndexer
)->Token
= NodeList
->Token
;
257 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
258 (*NodeIndexer
)->Offset
= Size
+ NodeStartOffset
;
261 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
263 (*NodeIndexer
)->Token
,
264 (*NodeIndexer
)->Object
,
265 (*NodeIndexer
)->Offset
268 Size
+= GetNamedComponentNodeSize (NodeList
);
276 /** Returns the size of the Root Complex node.
278 @param [in] Node Pointer to Root Complex node.
280 @retval Size of the Root Complex node.
284 GetRootComplexNodeSize (
285 IN CONST CM_ARM_ROOT_COMPLEX_NODE
* Node
288 ASSERT (Node
!= NULL
);
290 /* Size of Root Complex node +
291 Size of ID mapping array
293 return sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
) +
294 (Node
->IdMappingCount
*
295 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
));
298 /** Returns the total size required for the Root Complex nodes and
299 updates the Node Indexer.
301 This function calculates the size required for the node group
302 and also populates the Node Indexer array with offsets for the
305 @param [in] NodeStartOffset Offset from the start of the
306 IORT where this node group starts.
307 @param [in] NodeList Pointer to Root Complex node list.
308 @param [in] NodeCount Count of the Root Complex nodes.
309 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
311 @retval Total size of the Root Complex nodes.
315 GetSizeofRootComplexNodes (
316 IN CONST UINT32 NodeStartOffset
,
317 IN CONST CM_ARM_ROOT_COMPLEX_NODE
* NodeList
,
319 IN OUT IORT_NODE_INDEXER
** CONST NodeIndexer
324 ASSERT (NodeList
!= NULL
);
327 while (NodeCount
-- != 0) {
328 (*NodeIndexer
)->Token
= NodeList
->Token
;
329 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
330 (*NodeIndexer
)->Offset
= Size
+ NodeStartOffset
;
333 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
335 (*NodeIndexer
)->Token
,
336 (*NodeIndexer
)->Object
,
337 (*NodeIndexer
)->Offset
340 Size
+= GetRootComplexNodeSize (NodeList
);
348 /** Returns the size of the SMMUv1/SMMUv2 node.
350 @param [in] Node Pointer to SMMUv1/SMMUv2 node list.
352 @retval Size of the SMMUv1/SMMUv2 node.
356 GetSmmuV1V2NodeSize (
357 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE
* Node
360 ASSERT (Node
!= NULL
);
362 /* Size of SMMU v1/SMMU v2 node +
363 Size of ID mapping array +
364 Size of context interrupt array +
365 Size of PMU interrupt array
367 return sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
) +
368 (Node
->IdMappingCount
*
369 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
)) +
370 (Node
->ContextInterruptCount
*
371 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
)) +
372 (Node
->PmuInterruptCount
*
373 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
));
376 /** Returns the total size required for the SMMUv1/SMMUv2 nodes and
377 updates the Node Indexer.
379 This function calculates the size required for the node group
380 and also populates the Node Indexer array with offsets for the
383 @param [in] NodeStartOffset Offset from the start of the
384 IORT where this node group starts.
385 @param [in] NodeList Pointer to SMMUv1/SMMUv2 node list.
386 @param [in] NodeCount Count of the SMMUv1/SMMUv2 nodes.
387 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
389 @retval Total size of the SMMUv1/SMMUv2 nodes.
393 GetSizeofSmmuV1V2Nodes (
394 IN CONST UINT32 NodeStartOffset
,
395 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE
* NodeList
,
397 IN OUT IORT_NODE_INDEXER
** CONST NodeIndexer
402 ASSERT (NodeList
!= NULL
);
405 while (NodeCount
-- != 0) {
406 (*NodeIndexer
)->Token
= NodeList
->Token
;
407 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
408 (*NodeIndexer
)->Offset
= Size
+ NodeStartOffset
;
411 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
413 (*NodeIndexer
)->Token
,
414 (*NodeIndexer
)->Object
,
415 (*NodeIndexer
)->Offset
418 Size
+= GetSmmuV1V2NodeSize (NodeList
);
425 /** Returns the size of the SMMUv3 node.
427 @param [in] Node Pointer to SMMUv3 node list.
429 @retval Total size of the SMMUv3 nodes.
434 IN CONST CM_ARM_SMMUV3_NODE
* Node
437 ASSERT (Node
!= NULL
);
439 /* Size of SMMU v1/SMMU v2 node +
440 Size of ID mapping array
442 return sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
) +
443 (Node
->IdMappingCount
*
444 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
));
447 /** Returns the total size required for the SMMUv3 nodes and
448 updates the Node Indexer.
450 This function calculates the size required for the node group
451 and also populates the Node Indexer array with offsets for the
454 @param [in] NodeStartOffset Offset from the start of the
455 IORT where this node group starts.
456 @param [in] NodeList Pointer to SMMUv3 node list.
457 @param [in] NodeCount Count of the SMMUv3 nodes.
458 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
460 @retval Total size of the SMMUv3 nodes.
464 GetSizeofSmmuV3Nodes (
465 IN CONST UINT32 NodeStartOffset
,
466 IN CONST CM_ARM_SMMUV3_NODE
* NodeList
,
468 IN OUT IORT_NODE_INDEXER
** CONST NodeIndexer
473 ASSERT (NodeList
!= NULL
);
476 while (NodeCount
-- != 0) {
477 (*NodeIndexer
)->Token
= NodeList
->Token
;
478 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
479 (*NodeIndexer
)->Offset
= Size
+ NodeStartOffset
;
482 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
484 (*NodeIndexer
)->Token
,
485 (*NodeIndexer
)->Object
,
486 (*NodeIndexer
)->Offset
489 Size
+= GetSmmuV3NodeSize (NodeList
);
496 /** Returns the size of the PMCG node.
498 @param [in] Node Pointer to PMCG node.
500 @retval Size of the PMCG node.
505 IN CONST CM_ARM_PMCG_NODE
* Node
508 ASSERT (Node
!= NULL
);
510 /* Size of PMCG node +
511 Size of ID mapping array
513 return sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
) +
514 (Node
->IdMappingCount
*
515 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
));
518 /** Returns the total size required for the PMCG nodes and
519 updates the Node Indexer.
521 This function calculates the size required for the node group
522 and also populates the Node Indexer array with offsets for the
525 @param [in] NodeStartOffset Offset from the start of the
526 IORT where this node group starts.
527 @param [in] NodeList Pointer to PMCG node list.
528 @param [in] NodeCount Count of the PMCG nodes.
529 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
531 @retval Total size of the PMCG nodes.
536 IN CONST UINT32 NodeStartOffset
,
537 IN CONST CM_ARM_PMCG_NODE
* NodeList
,
539 IN OUT IORT_NODE_INDEXER
** CONST NodeIndexer
544 ASSERT (NodeList
!= NULL
);
547 while (NodeCount
-- != 0) {
548 (*NodeIndexer
)->Token
= NodeList
->Token
;
549 (*NodeIndexer
)->Object
= (VOID
*)NodeList
;
550 (*NodeIndexer
)->Offset
= Size
+ NodeStartOffset
;
553 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
555 (*NodeIndexer
)->Token
,
556 (*NodeIndexer
)->Object
,
557 (*NodeIndexer
)->Offset
560 Size
+= GetPmcgNodeSize (NodeList
);
567 /** Returns the offset of the Node referenced by the Token.
569 @param [in] NodeIndexer Pointer to node indexer array.
570 @param [in] NodeCount Count of the nodes.
571 @param [in] Token Reference token for the node.
572 @param [out] NodeOffset Offset of the node from the
573 start of the IORT table.
575 @retval EFI_SUCCESS Success.
576 @retval EFI_NOT_FOUND No matching token reference
577 found in node indexer array.
581 GetNodeOffsetReferencedByToken (
582 IN IORT_NODE_INDEXER
* NodeIndexer
,
584 IN CM_OBJECT_TOKEN Token
,
585 OUT UINT32
* NodeOffset
590 "IORT: Node Indexer: Search Token = %p\n",
593 while (NodeCount
-- != 0) {
596 "IORT: Node Indexer: NodeIndexer->Token = %p, Offset = %d\n",
600 if (NodeIndexer
->Token
== Token
) {
601 *NodeOffset
= NodeIndexer
->Offset
;
604 "IORT: Node Indexer: Token = %p, Found\n",
613 "IORT: Node Indexer: Token = %p, Not Found\n",
616 return EFI_NOT_FOUND
;
619 /** Update the Id Mapping Array.
621 This function retrieves the Id Mapping Array object referenced by the
622 IdMappingToken and updates the IdMapArray.
624 @param [in] This Pointer to the table Generator.
625 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
627 @param [in] IdMapArray Pointer to an array of Id Mappings.
628 @param [in] IdCount Number of Id Mappings.
629 @param [in] IdMappingToken Reference Token for retrieving the
630 Id Mapping Array object.
632 @retval EFI_SUCCESS Table generated successfully.
633 @retval EFI_INVALID_PARAMETER A parameter is invalid.
634 @retval EFI_NOT_FOUND The required object was not found.
639 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
640 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
641 IN EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
,
643 IN CONST CM_OBJECT_TOKEN IdMappingToken
647 CM_ARM_ID_MAPPING
* IdMappings
;
648 UINT32 IdMappingCount
;
649 ACPI_IORT_GENERATOR
* Generator
;
651 ASSERT (IdMapArray
!= NULL
);
653 Generator
= (ACPI_IORT_GENERATOR
*)This
;
655 // Get the Id Mapping Array
656 Status
= GetEArmObjIdMapping (
662 if (EFI_ERROR (Status
)) {
665 "ERROR: IORT: Failed to get Id Mapping array. Status = %r\n",
671 if (IdMappingCount
< IdCount
) {
674 "ERROR: IORT: Failed to get the required number of Id Mappings.\n"
676 return EFI_NOT_FOUND
;
679 // Populate the Id Mapping array
680 while (IdCount
-- != 0) {
681 Status
= GetNodeOffsetReferencedByToken (
682 Generator
->NodeIndexer
,
683 Generator
->IortNodeCount
,
684 IdMappings
->OutputReferenceToken
,
685 &IdMapArray
->OutputReference
687 if (EFI_ERROR (Status
)) {
690 "ERROR: IORT: Failed to get Output Reference for ITS Identifier array."
691 "Reference Token = %p"
693 IdMappings
->OutputReferenceToken
,
699 IdMapArray
->InputBase
= IdMappings
->InputBase
;
700 IdMapArray
->NumIds
= IdMappings
->NumIds
;
701 IdMapArray
->OutputBase
= IdMappings
->OutputBase
;
702 IdMapArray
->Flags
= IdMappings
->Flags
;
706 } // Id Mapping array
711 /** Update the ITS Group Node Information.
713 @param [in] This Pointer to the table Generator.
714 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
716 @param [in] Iort Pointer to IORT table structure.
717 @param [in] NodesStartOffset Offset for the start of the ITS Group
719 @param [in] NodeList Pointer to an array of ITS Group Node
721 @param [in] NodeCount Number of ITS Group Node Objects.
723 @retval EFI_SUCCESS Table generated successfully.
724 @retval EFI_INVALID_PARAMETER A parameter is invalid.
725 @retval EFI_NOT_FOUND The required object was not found.
730 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
731 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
732 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
733 IN CONST UINT32 NodesStartOffset
,
734 IN CONST CM_ARM_ITS_GROUP_NODE
* NodeList
,
739 EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
* ItsGroupNode
;
741 CM_ARM_ITS_IDENTIFIER
* ItsIdentifier
;
742 UINT32 ItsIdentifierCount
;
745 ASSERT (Iort
!= NULL
);
747 ItsGroupNode
= (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
*)((UINT8
*)Iort
+
750 while (NodeCount
-- != 0) {
751 // Populate the node header
752 ItsGroupNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_ITS_GROUP
;
753 ItsGroupNode
->Node
.Length
= GetItsGroupNodeSize (NodeList
);
754 ItsGroupNode
->Node
.Revision
= 0;
755 ItsGroupNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
756 ItsGroupNode
->Node
.NumIdMappings
= 0;
757 ItsGroupNode
->Node
.IdReference
= 0;
759 // IORT specific data
760 ItsGroupNode
->NumItsIdentifiers
= NodeList
->ItsIdCount
;
761 ItsIds
= (UINT32
*)((UINT8
*)ItsGroupNode
+
762 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
));
764 Status
= GetEArmObjGicItsIdentifierArray (
766 NodeList
->ItsIdToken
,
770 if (EFI_ERROR (Status
)) {
773 "ERROR: IORT: Failed to get ITS Identifier array. Status = %r\n",
779 if (ItsIdentifierCount
< ItsGroupNode
->NumItsIdentifiers
) {
782 "ERROR: IORT: Failed to get the required number of ITS Identifiers.\n"
784 return EFI_NOT_FOUND
;
787 // Populate the ITS identifier array
788 for (IdIndex
= 0; IdIndex
< ItsGroupNode
->NumItsIdentifiers
; IdIndex
++) {
789 ItsIds
[IdIndex
] = ItsIdentifier
[IdIndex
].ItsId
;
790 } // ITS identifier array
792 // Next IORT Group Node
793 ItsGroupNode
= (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE
*)((UINT8
*)ItsGroupNode
+
794 ItsGroupNode
->Node
.Length
);
801 /** Update the Named Component Node Information.
803 This function updates the Named Component node information in the IORT
806 @param [in] This Pointer to the table Generator.
807 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
809 @param [in] Iort Pointer to IORT table structure.
810 @param [in] NodesStartOffset Offset for the start of the Named
812 @param [in] NodeList Pointer to an array of Named Component
814 @param [in] NodeCount Number of Named Component Node Objects.
816 @retval EFI_SUCCESS Table generated successfully.
817 @retval EFI_INVALID_PARAMETER A parameter is invalid.
818 @retval EFI_NOT_FOUND The required object was not found.
822 AddNamedComponentNodes (
823 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
824 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
825 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
826 IN CONST UINT32 NodesStartOffset
,
827 IN CONST CM_ARM_NAMED_COMPONENT_NODE
* NodeList
,
832 EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
* NcNode
;
833 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
834 UINT32 ObjectNameLenght
;
837 ASSERT (Iort
!= NULL
);
839 NcNode
= (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
*)((UINT8
*)Iort
+
842 while (NodeCount
-- != 0) {
843 // Populate the node header
844 NcNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_NAMED_COMP
;
845 NcNode
->Node
.Length
=
846 GetNamedComponentNodeSize (NodeList
);
847 NcNode
->Node
.Revision
= 2;
848 NcNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
849 NcNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
851 ObjectNameLenght
= AsciiStrLen (NodeList
->ObjectName
) + 1;
852 NcNode
->Node
.IdReference
=
853 sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
) +
854 (ALIGN_VALUE (ObjectNameLenght
, 4));
856 // Named Component specific data
857 NcNode
->Flags
= NodeList
->Flags
;
858 NcNode
->CacheCoherent
= NodeList
->CacheCoherent
;
859 NcNode
->AllocationHints
= NodeList
->AllocationHints
;
860 NcNode
->Reserved
= EFI_ACPI_RESERVED_WORD
;
861 NcNode
->MemoryAccessFlags
= NodeList
->MemoryAccessFlags
;
862 NcNode
->AddressSizeLimit
= NodeList
->AddressSizeLimit
;
864 // Copy the object name
865 ObjectName
= (CHAR8
*)((UINT8
*)NcNode
+
866 sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
));
867 Status
= AsciiStrCpyS (
872 if (EFI_ERROR (Status
)) {
875 "ERROR: IORT: Failed to copy Object Name. Status = %r\n",
881 if ((NodeList
->IdMappingCount
> 0) &&
882 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
883 // Ids for Named Component
884 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)NcNode
+
885 NcNode
->Node
.IdReference
);
887 Status
= AddIdMappingArray (
891 NodeList
->IdMappingCount
,
892 NodeList
->IdMappingToken
894 if (EFI_ERROR (Status
)) {
897 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
904 // Next Named Component Node
905 NcNode
= (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE
*)((UINT8
*)NcNode
+
906 NcNode
->Node
.Length
);
908 } // Named Component Node
913 /** Update the Root Complex Node Information.
915 This function updates the Root Complex node information in the IORT table.
917 @param [in] This Pointer to the table Generator.
918 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
920 @param [in] Iort Pointer to IORT table structure.
921 @param [in] NodesStartOffset Offset for the start of the Root Complex
923 @param [in] NodeList Pointer to an array of Root Complex Node
925 @param [in] NodeCount Number of Root Complex Node Objects.
927 @retval EFI_SUCCESS Table generated successfully.
928 @retval EFI_INVALID_PARAMETER A parameter is invalid.
929 @retval EFI_NOT_FOUND The required object was not found.
933 AddRootComplexNodes (
934 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
935 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
936 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
937 IN CONST UINT32 NodesStartOffset
,
938 IN CONST CM_ARM_ROOT_COMPLEX_NODE
* NodeList
,
943 EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
* RcNode
;
944 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
946 ASSERT (Iort
!= NULL
);
948 RcNode
= (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
*)((UINT8
*)Iort
+
951 while (NodeCount
-- != 0) {
952 // Populate the node header
953 RcNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_ROOT_COMPLEX
;
954 RcNode
->Node
.Length
= GetRootComplexNodeSize (NodeList
);
955 RcNode
->Node
.Revision
= 1;
956 RcNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
957 RcNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
958 RcNode
->Node
.IdReference
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
);
960 // Root Complex specific data
961 RcNode
->CacheCoherent
= NodeList
->CacheCoherent
;
962 RcNode
->AllocationHints
= NodeList
->AllocationHints
;
963 RcNode
->Reserved
= EFI_ACPI_RESERVED_WORD
;
964 RcNode
->MemoryAccessFlags
= NodeList
->MemoryAccessFlags
;
965 RcNode
->AtsAttribute
= NodeList
->AtsAttribute
;
966 RcNode
->PciSegmentNumber
= NodeList
->PciSegmentNumber
;
967 RcNode
->MemoryAddressSize
= NodeList
->MemoryAddressSize
;
968 RcNode
->Reserved1
[0] = EFI_ACPI_RESERVED_BYTE
;
969 RcNode
->Reserved1
[1] = EFI_ACPI_RESERVED_BYTE
;
970 RcNode
->Reserved1
[2] = EFI_ACPI_RESERVED_BYTE
;
972 if ((NodeList
->IdMappingCount
> 0) &&
973 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
974 // Ids for Root Complex
975 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)RcNode
+
976 RcNode
->Node
.IdReference
);
977 Status
= AddIdMappingArray (
981 NodeList
->IdMappingCount
,
982 NodeList
->IdMappingToken
984 if (EFI_ERROR (Status
)) {
987 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
994 // Next Root Complex Node
995 RcNode
= (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE
*)((UINT8
*)RcNode
+
996 RcNode
->Node
.Length
);
998 } // Root Complex Node
1003 /** Update the SMMU Interrupt Array.
1005 This function retrieves the InterruptArray object referenced by the
1006 InterruptToken and updates the SMMU InterruptArray.
1008 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1010 @param [in, out] InterruptArray Pointer to an array of Interrupts.
1011 @param [in] InterruptCount Number of entries in the InterruptArray.
1012 @param [in] InterruptToken Reference Token for retrieving the SMMU
1013 InterruptArray object.
1015 @retval EFI_SUCCESS Table generated successfully.
1016 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1017 @retval EFI_NOT_FOUND The required object was not found.
1021 AddSmmuInterrruptArray (
1022 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1023 IN OUT EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
* InterruptArray
,
1024 IN UINT32 InterruptCount
,
1025 IN CONST CM_OBJECT_TOKEN InterruptToken
1029 CM_ARM_SMMU_INTERRUPT
* SmmuInterrupt
;
1030 UINT32 SmmuInterruptCount
;
1032 ASSERT (InterruptArray
!= NULL
);
1034 // Get the SMMU Interrupt Array
1035 Status
= GetEArmObjSmmuInterruptArray (
1041 if (EFI_ERROR (Status
)) {
1044 "ERROR: IORT: Failed to get SMMU Interrupt array. Status = %r\n",
1050 if (SmmuInterruptCount
< InterruptCount
) {
1053 "ERROR: IORT: Failed to get the required number of SMMU Interrupts.\n"
1055 return EFI_NOT_FOUND
;
1058 // Populate the Id Mapping array
1059 while (InterruptCount
-- != 0) {
1060 InterruptArray
->Interrupt
= SmmuInterrupt
->Interrupt
;
1061 InterruptArray
->InterruptFlags
= SmmuInterrupt
->Flags
;
1064 } // Id Mapping array
1069 /** Update the SMMU v1/v2 Node Information.
1071 @param [in] This Pointer to the table Generator.
1072 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1074 @param [in] Iort Pointer to IORT table structure.
1075 @param [in] NodesStartOffset Offset for the start of the SMMU v1/v2
1077 @param [in] NodeList Pointer to an array of SMMU v1/v2 Node
1079 @param [in] NodeCount Number of SMMU v1/v2 Node Objects.
1081 @retval EFI_SUCCESS Table generated successfully.
1082 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1083 @retval EFI_NOT_FOUND The required object was not found.
1088 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1089 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1090 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
1091 IN CONST UINT32 NodesStartOffset
,
1092 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE
* NodeList
,
1097 EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
* SmmuNode
;
1098 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
1100 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
* ContextInterruptArray
;
1101 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
* PmuInterruptArray
;
1103 ASSERT (Iort
!= NULL
);
1105 SmmuNode
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
*)((UINT8
*)Iort
+
1108 while (NodeCount
-- != 0) {
1109 // Populate the node header
1110 SmmuNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_SMMUv1v2
;
1111 SmmuNode
->Node
.Length
= GetSmmuV1V2NodeSize (NodeList
);
1112 SmmuNode
->Node
.Revision
= 0;
1113 SmmuNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
1114 SmmuNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1115 SmmuNode
->Node
.IdReference
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
) +
1116 (NodeList
->ContextInterruptCount
*
1117 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
)) +
1118 (NodeList
->PmuInterruptCount
*
1119 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
));
1121 // SMMU v1/v2 specific data
1122 SmmuNode
->Base
= NodeList
->BaseAddress
;
1123 SmmuNode
->Span
= NodeList
->Span
;
1124 SmmuNode
->Model
= NodeList
->Model
;
1125 SmmuNode
->Flags
= NodeList
->Flags
;
1127 // Reference to Global Interrupt Array
1128 SmmuNode
->GlobalInterruptArrayRef
=
1129 OFFSET_OF (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
, SMMU_NSgIrpt
);
1131 // Context Interrupt
1132 SmmuNode
->NumContextInterrupts
= NodeList
->ContextInterruptCount
;
1133 SmmuNode
->ContextInterruptArrayRef
=
1134 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
);
1135 ContextInterruptArray
=
1136 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
*)((UINT8
*)SmmuNode
+
1137 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
));
1140 SmmuNode
->NumPmuInterrupts
= NodeList
->PmuInterruptCount
;
1141 SmmuNode
->PmuInterruptArrayRef
= SmmuNode
->ContextInterruptArrayRef
+
1142 (NodeList
->ContextInterruptCount
*
1143 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
));
1145 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT
*)((UINT8
*)SmmuNode
+
1146 SmmuNode
->PmuInterruptArrayRef
);
1148 SmmuNode
->SMMU_NSgIrpt
= NodeList
->SMMU_NSgIrpt
;
1149 SmmuNode
->SMMU_NSgIrptFlags
= NodeList
->SMMU_NSgIrptFlags
;
1150 SmmuNode
->SMMU_NSgCfgIrpt
= NodeList
->SMMU_NSgCfgIrpt
;
1151 SmmuNode
->SMMU_NSgCfgIrptFlags
= NodeList
->SMMU_NSgCfgIrptFlags
;
1153 // Add Context Interrupt Array
1154 Status
= AddSmmuInterrruptArray (
1156 ContextInterruptArray
,
1157 SmmuNode
->NumContextInterrupts
,
1158 NodeList
->ContextInterruptToken
1160 if (EFI_ERROR (Status
)) {
1163 "ERROR: IORT: Failed to Context Interrupt Array. Status = %r\n",
1169 // Add PMU Interrupt Array
1170 if ((SmmuNode
->NumPmuInterrupts
> 0) &&
1171 (NodeList
->PmuInterruptToken
!= CM_NULL_TOKEN
)) {
1172 Status
= AddSmmuInterrruptArray (
1175 SmmuNode
->NumPmuInterrupts
,
1176 NodeList
->PmuInterruptToken
1178 if (EFI_ERROR (Status
)) {
1181 "ERROR: IORT: Failed to PMU Interrupt Array. Status = %r\n",
1188 if ((NodeList
->IdMappingCount
> 0) &&
1189 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
1190 // Ids for SMMU v1/v2 Node
1191 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)SmmuNode
+
1192 SmmuNode
->Node
.IdReference
);
1193 Status
= AddIdMappingArray (
1197 NodeList
->IdMappingCount
,
1198 NodeList
->IdMappingToken
1200 if (EFI_ERROR (Status
)) {
1203 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1209 // Next SMMU v1/v2 Node
1210 SmmuNode
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE
*)((UINT8
*)SmmuNode
+
1211 SmmuNode
->Node
.Length
);
1213 } // SMMU v1/v2 Node
1218 /** Update the SMMUv3 Node Information.
1220 This function updates the SMMUv3 node information in the IORT table.
1222 @param [in] This Pointer to the table Generator.
1223 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1225 @param [in] Iort Pointer to IORT table structure.
1226 @param [in] NodesStartOffset Offset for the start of the SMMUv3 Nodes.
1227 @param [in] NodeList Pointer to an array of SMMUv3 Node Objects.
1228 @param [in] NodeCount Number of SMMUv3 Node Objects.
1230 @retval EFI_SUCCESS Table generated successfully.
1231 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1232 @retval EFI_NOT_FOUND The required object was not found.
1237 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1238 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1239 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
1240 IN CONST UINT32 NodesStartOffset
,
1241 IN CONST CM_ARM_SMMUV3_NODE
* NodeList
,
1246 EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
* SmmuV3Node
;
1247 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
1249 ASSERT (Iort
!= NULL
);
1251 SmmuV3Node
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
*)((UINT8
*)Iort
+
1254 while (NodeCount
-- != 0) {
1255 // Populate the node header
1256 SmmuV3Node
->Node
.Type
= EFI_ACPI_IORT_TYPE_SMMUv3
;
1257 SmmuV3Node
->Node
.Length
= GetSmmuV3NodeSize (NodeList
);
1258 SmmuV3Node
->Node
.Revision
= 2;
1259 SmmuV3Node
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
1260 SmmuV3Node
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1261 SmmuV3Node
->Node
.IdReference
=
1262 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
);
1264 // SMMUv3 specific data
1265 SmmuV3Node
->Base
= NodeList
->BaseAddress
;
1266 SmmuV3Node
->Flags
= NodeList
->Flags
;
1267 SmmuV3Node
->Reserved
= EFI_ACPI_RESERVED_WORD
;
1268 SmmuV3Node
->VatosAddress
= NodeList
->VatosAddress
;
1269 SmmuV3Node
->Model
= NodeList
->Model
;
1270 SmmuV3Node
->Event
= NodeList
->EventInterrupt
;
1271 SmmuV3Node
->Pri
= NodeList
->PriInterrupt
;
1272 SmmuV3Node
->Gerr
= NodeList
->GerrInterrupt
;
1273 SmmuV3Node
->Sync
= NodeList
->SyncInterrupt
;
1275 if ((SmmuV3Node
->Flags
& EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN
) != 0) {
1276 // The Proximity Domain Valid flag is set to 1
1277 SmmuV3Node
->ProximityDomain
= NodeList
->ProximityDomain
;
1279 SmmuV3Node
->ProximityDomain
= 0;
1282 if ((SmmuV3Node
->Event
!= 0) && (SmmuV3Node
->Pri
!= 0) &&
1283 (SmmuV3Node
->Gerr
!= 0) && (SmmuV3Node
->Sync
!= 0)) {
1284 // If all the SMMU control interrupts are GSIV based,
1285 // the DeviceID mapping index field is ignored.
1286 SmmuV3Node
->DeviceIdMappingIndex
= 0;
1288 SmmuV3Node
->DeviceIdMappingIndex
= NodeList
->DeviceIdMappingIndex
;
1291 if ((NodeList
->IdMappingCount
> 0) &&
1292 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
1293 // Ids for SMMUv3 node
1294 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)SmmuV3Node
+
1295 SmmuV3Node
->Node
.IdReference
);
1296 Status
= AddIdMappingArray (
1300 NodeList
->IdMappingCount
,
1301 NodeList
->IdMappingToken
1303 if (EFI_ERROR (Status
)) {
1306 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1314 SmmuV3Node
= (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE
*)((UINT8
*)SmmuV3Node
+
1315 SmmuV3Node
->Node
.Length
);
1322 /** Update the PMCG Node Information.
1324 This function updates the PMCG node information in the IORT table.
1326 @param [in] This Pointer to the table Generator.
1327 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1329 @param [in] Iort Pointer to IORT table structure.
1330 @param [in] NodesStartOffset Offset for the start of the PMCG Nodes.
1331 @param [in] NodeList Pointer to an array of PMCG Node Objects.
1332 @param [in] NodeCount Number of PMCG Node Objects.
1334 @retval EFI_SUCCESS Table generated successfully.
1335 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1336 @retval EFI_NOT_FOUND The required object was not found.
1341 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1342 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1343 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
,
1344 IN CONST UINT32 NodesStartOffset
,
1345 IN CONST CM_ARM_PMCG_NODE
* NodeList
,
1350 EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
* PmcgNode
;
1351 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
* IdMapArray
;
1352 ACPI_IORT_GENERATOR
* Generator
;
1354 ASSERT (Iort
!= NULL
);
1356 Generator
= (ACPI_IORT_GENERATOR
*)This
;
1357 PmcgNode
= (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
*)((UINT8
*)Iort
+
1360 while (NodeCount
-- != 0) {
1361 // Populate the node header
1362 PmcgNode
->Node
.Type
= EFI_ACPI_IORT_TYPE_PMCG
;
1363 PmcgNode
->Node
.Length
= GetPmcgNodeSize (NodeList
);
1364 PmcgNode
->Node
.Revision
= 1;
1365 PmcgNode
->Node
.Reserved
= EFI_ACPI_RESERVED_DWORD
;
1366 PmcgNode
->Node
.NumIdMappings
= NodeList
->IdMappingCount
;
1367 PmcgNode
->Node
.IdReference
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
);
1369 // PMCG specific data
1370 PmcgNode
->Base
= NodeList
->BaseAddress
;
1371 PmcgNode
->OverflowInterruptGsiv
= NodeList
->OverflowInterrupt
;
1372 PmcgNode
->Page1Base
= NodeList
->Page1BaseAddress
;
1374 Status
= GetNodeOffsetReferencedByToken (
1375 Generator
->NodeIndexer
,
1376 Generator
->IortNodeCount
,
1377 NodeList
->ReferenceToken
,
1378 &PmcgNode
->NodeReference
1380 if (EFI_ERROR (Status
)) {
1383 "ERROR: IORT: Failed to get Output Reference for PMCG Node."
1384 "Reference Token = %p"
1386 NodeList
->ReferenceToken
,
1392 if ((NodeList
->IdMappingCount
> 0) &&
1393 (NodeList
->IdMappingToken
!= CM_NULL_TOKEN
)) {
1394 // Ids for PMCG node
1395 IdMapArray
= (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE
*)((UINT8
*)PmcgNode
+
1396 PmcgNode
->Node
.IdReference
);
1398 Status
= AddIdMappingArray (
1402 NodeList
->IdMappingCount
,
1403 NodeList
->IdMappingToken
1405 if (EFI_ERROR (Status
)) {
1408 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1416 PmcgNode
= (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE
*)((UINT8
*)PmcgNode
+
1417 PmcgNode
->Node
.Length
);
1424 /** Construct the IORT ACPI table.
1426 This function invokes the Configuration Manager protocol interface
1427 to get the required hardware information for generating the ACPI
1430 If this function allocates any resources then they must be freed
1431 in the FreeXXXXTableResources function.
1433 @param [in] This Pointer to the table generator.
1434 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1435 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1437 @param [out] Table Pointer to the constructed ACPI Table.
1439 @retval EFI_SUCCESS Table generated successfully.
1440 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1441 @retval EFI_NOT_FOUND The required object was not found.
1442 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
1443 Manager is less than the Object size for the
1450 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1451 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
1452 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1453 OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
1458 UINT32 IortNodeCount
;
1460 UINT32 ItsGroupNodeCount
;
1461 UINT32 NamedComponentNodeCount
;
1462 UINT32 RootComplexNodeCount
;
1463 UINT32 SmmuV1V2NodeCount
;
1464 UINT32 SmmuV3NodeCount
;
1465 UINT32 PmcgNodeCount
;
1467 UINT32 ItsGroupOffset
;
1468 UINT32 NamedComponentOffset
;
1469 UINT32 RootComplexOffset
;
1470 UINT32 SmmuV1V2Offset
;
1471 UINT32 SmmuV3Offset
;
1474 CM_ARM_ITS_GROUP_NODE
* ItsGroupNodeList
;
1475 CM_ARM_NAMED_COMPONENT_NODE
* NamedComponentNodeList
;
1476 CM_ARM_ROOT_COMPLEX_NODE
* RootComplexNodeList
;
1477 CM_ARM_SMMUV1_SMMUV2_NODE
* SmmuV1V2NodeList
;
1478 CM_ARM_SMMUV3_NODE
* SmmuV3NodeList
;
1479 CM_ARM_PMCG_NODE
* PmcgNodeList
;
1481 EFI_ACPI_6_0_IO_REMAPPING_TABLE
* Iort
;
1482 IORT_NODE_INDEXER
* NodeIndexer
;
1483 ACPI_IORT_GENERATOR
* Generator
;
1485 ASSERT (This
!= NULL
);
1486 ASSERT (AcpiTableInfo
!= NULL
);
1487 ASSERT (CfgMgrProtocol
!= NULL
);
1488 ASSERT (Table
!= NULL
);
1489 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
1490 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
1492 if ((AcpiTableInfo
->AcpiTableRevision
< This
->MinAcpiTableRevision
) ||
1493 (AcpiTableInfo
->AcpiTableRevision
> This
->AcpiTableRevision
)) {
1496 "ERROR: IORT: Requested table revision = %d, is not supported."
1497 "Supported table revision: Minimum = %d, Maximum = %d\n",
1498 AcpiTableInfo
->AcpiTableRevision
,
1499 This
->MinAcpiTableRevision
,
1500 This
->AcpiTableRevision
1502 return EFI_INVALID_PARAMETER
;
1505 Generator
= (ACPI_IORT_GENERATOR
*)This
;
1508 // Get the ITS group node info
1509 Status
= GetEArmObjItsGroup (
1515 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1518 "ERROR: IORT: Failed to get ITS Group Node Info. Status = %r\n",
1524 // Add the ITS group node count
1525 IortNodeCount
= ItsGroupNodeCount
;
1527 // Get the Named component node info
1528 Status
= GetEArmObjNamedComponent (
1531 &NamedComponentNodeList
,
1532 &NamedComponentNodeCount
1534 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1537 "ERROR: IORT: Failed to get Named Component Node Info. Status = %r\n",
1543 // Add the Named Component group count
1544 IortNodeCount
+= NamedComponentNodeCount
;
1546 // Get the Root complex node info
1547 Status
= GetEArmObjRootComplex (
1550 &RootComplexNodeList
,
1551 &RootComplexNodeCount
1553 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1556 "ERROR: IORT: Failed to get Root Complex Node Info. Status = %r\n",
1562 // Add the Root Complex node count
1563 IortNodeCount
+= RootComplexNodeCount
;
1565 // Get the SMMU v1/v2 node info
1566 Status
= GetEArmObjSmmuV1SmmuV2 (
1572 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1575 "ERROR: IORT: Failed to get SMMUv1/SMMUv2 Node Info. Status = %r\n",
1581 // Add the SMMU v1/v2 node count
1582 IortNodeCount
+= SmmuV1V2NodeCount
;
1584 // Get the SMMUv3 node info
1585 Status
= GetEArmObjSmmuV3 (
1591 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1594 "ERROR: IORT: Failed to get SMMUv3 Node Info. Status = %r\n",
1600 // Add the SMMUv3 node count
1601 IortNodeCount
+= SmmuV3NodeCount
;
1603 // Get the PMCG node info
1604 Status
= GetEArmObjPmcg (
1610 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1613 "ERROR: IORT: Failed to get PMCG Node Info. Status = %r\n",
1619 // Add the PMCG node count
1620 IortNodeCount
+= PmcgNodeCount
;
1622 // Allocate Node Indexer array
1623 NodeIndexer
= (IORT_NODE_INDEXER
*)AllocateZeroPool (
1624 (sizeof (IORT_NODE_INDEXER
) *
1627 if (NodeIndexer
== NULL
) {
1628 Status
= EFI_OUT_OF_RESOURCES
;
1631 "ERROR: IORT: Failed to allocate memory for Node Indexer" \
1638 DEBUG ((DEBUG_INFO
, "INFO: NodeIndexer = %p\n", NodeIndexer
));
1639 Generator
->IortNodeCount
= IortNodeCount
;
1640 Generator
->NodeIndexer
= NodeIndexer
;
1642 // Calculate the size of the IORT table
1643 TableSize
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE
);
1646 if (ItsGroupNodeCount
> 0) {
1647 ItsGroupOffset
= TableSize
;
1648 // Size of ITS Group node list.
1649 TableSize
+= GetSizeofItsGroupNodes (
1657 // Named Component Nodes
1658 if (NamedComponentNodeCount
> 0) {
1659 NamedComponentOffset
= TableSize
;
1660 // Size of Named Component node list.
1661 TableSize
+= GetSizeofNamedComponentNodes (
1662 NamedComponentOffset
,
1663 NamedComponentNodeList
,
1664 NamedComponentNodeCount
,
1669 // Root Complex Nodes
1670 if (RootComplexNodeCount
> 0) {
1671 RootComplexOffset
= TableSize
;
1672 // Size of Root Complex node list.
1673 TableSize
+= GetSizeofRootComplexNodes (
1675 RootComplexNodeList
,
1676 RootComplexNodeCount
,
1681 // SMMUv1/SMMUv2 Nodes
1682 if (SmmuV1V2NodeCount
> 0) {
1683 SmmuV1V2Offset
= TableSize
;
1684 // Size of SMMUv1/SMMUv2 node list.
1685 TableSize
+= GetSizeofSmmuV1V2Nodes (
1694 if (SmmuV3NodeCount
> 0) {
1695 SmmuV3Offset
= TableSize
;
1696 // Size of SMMUv3 node list.
1697 TableSize
+= GetSizeofSmmuV3Nodes (
1706 if (PmcgNodeCount
> 0) {
1707 PmcgOffset
= TableSize
;
1708 // Size of PMCG node list.
1709 TableSize
+= GetSizeofPmcgNodes (
1720 " IortNodeCount = %d\n" \
1721 " TableSize = %d\n",
1728 " ItsGroupNodeCount = %d\n" \
1729 " ItsGroupOffset = %d\n",
1736 " NamedComponentNodeCount = %d\n" \
1737 " NamedComponentOffset = %d\n",
1738 NamedComponentNodeCount
,
1739 NamedComponentOffset
1744 " RootComplexNodeCount = %d\n" \
1745 " RootComplexOffset = %d\n",
1746 RootComplexNodeCount
,
1752 " SmmuV1V2NodeCount = %d\n" \
1753 " SmmuV1V2Offset = %d\n",
1760 " SmmuV3NodeCount = %d\n" \
1761 " SmmuV3Offset = %d\n",
1768 " PmcgNodeCount = %d\n" \
1769 " PmcgOffset = %d\n",
1774 // Allocate the Buffer for IORT table
1775 *Table
= (EFI_ACPI_DESCRIPTION_HEADER
*)AllocateZeroPool (TableSize
);
1776 if (*Table
== NULL
) {
1777 Status
= EFI_OUT_OF_RESOURCES
;
1780 "ERROR: IORT: Failed to allocate memory for IORT Table, Size = %d," \
1788 Iort
= (EFI_ACPI_6_0_IO_REMAPPING_TABLE
*)*Table
;
1792 "IORT: Iort = 0x%p TableSize = 0x%x\n",
1797 Status
= AddAcpiHeader (
1801 AcpiTableInfo
->AcpiTableRevision
,
1804 if (EFI_ERROR (Status
)) {
1807 "ERROR: IORT: Failed to add ACPI header. Status = %r\n",
1813 // Update IORT table
1814 Iort
->NumNodes
= IortNodeCount
;
1815 Iort
->NodeOffset
= sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE
);
1816 Iort
->Reserved
= EFI_ACPI_RESERVED_DWORD
;
1818 if (ItsGroupNodeCount
> 0) {
1819 Status
= AddItsGroupNodes (
1827 if (EFI_ERROR (Status
)) {
1830 "ERROR: IORT: Failed to add ITS Group Node. Status = %r\n",
1837 if (NamedComponentNodeCount
> 0) {
1838 Status
= AddNamedComponentNodes (
1842 NamedComponentOffset
,
1843 NamedComponentNodeList
,
1844 NamedComponentNodeCount
1846 if (EFI_ERROR (Status
)) {
1849 "ERROR: IORT: Failed to add Named Component Node. Status = %r\n",
1856 if (RootComplexNodeCount
> 0) {
1857 Status
= AddRootComplexNodes (
1862 RootComplexNodeList
,
1863 RootComplexNodeCount
1865 if (EFI_ERROR (Status
)) {
1868 "ERROR: IORT: Failed to add Root Complex Node. Status = %r\n",
1875 if (SmmuV1V2NodeCount
> 0) {
1876 Status
= AddSmmuV1V2Nodes (
1884 if (EFI_ERROR (Status
)) {
1887 "ERROR: IORT: Failed to add SMMU v1/v2 Node. Status = %r\n",
1894 if (SmmuV3NodeCount
> 0) {
1895 Status
= AddSmmuV3Nodes (
1903 if (EFI_ERROR (Status
)) {
1906 "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
1913 if (PmcgNodeCount
> 0) {
1914 Status
= AddPmcgNodes (
1922 if (EFI_ERROR (Status
)) {
1925 "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
1935 if (Generator
->NodeIndexer
!= NULL
) {
1936 FreePool (Generator
->NodeIndexer
);
1937 Generator
->NodeIndexer
= NULL
;
1940 if (*Table
!= NULL
) {
1947 /** Free any resources allocated for constructing the IORT
1949 @param [in] This Pointer to the table generator.
1950 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1951 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1953 @param [in, out] Table Pointer to the ACPI Table.
1955 @retval EFI_SUCCESS The resources were freed successfully.
1956 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1960 FreeIortTableResources (
1961 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1962 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
1963 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1964 IN OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
1967 ACPI_IORT_GENERATOR
* Generator
;
1968 ASSERT (This
!= NULL
);
1969 ASSERT (AcpiTableInfo
!= NULL
);
1970 ASSERT (CfgMgrProtocol
!= NULL
);
1971 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
1972 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
1974 Generator
= (ACPI_IORT_GENERATOR
*)This
;
1976 // Free any memory allocated by the generator
1977 if (Generator
->NodeIndexer
!= NULL
) {
1978 FreePool (Generator
->NodeIndexer
);
1979 Generator
->NodeIndexer
= NULL
;
1982 if ((Table
== NULL
) || (*Table
== NULL
)) {
1983 DEBUG ((DEBUG_ERROR
, "ERROR: IORT: Invalid Table Pointer\n"));
1984 ASSERT ((Table
!= NULL
) && (*Table
!= NULL
));
1985 return EFI_INVALID_PARAMETER
;
1993 /** The IORT Table Generator revision.
1995 #define IORT_GENERATOR_REVISION CREATE_REVISION (1, 0)
1997 /** The interface for the MADT Table Generator.
2000 ACPI_IORT_GENERATOR IortGenerator
= {
2001 // ACPI table generator header
2004 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdIort
),
2005 // Generator Description
2006 L
"ACPI.STD.IORT.GENERATOR",
2007 // ACPI Table Signature
2008 EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE
,
2009 // ACPI Table Revision supported by this Generator
2010 EFI_ACPI_IO_REMAPPING_TABLE_REVISION
,
2011 // Minimum supported ACPI Table Revision
2012 EFI_ACPI_IO_REMAPPING_TABLE_REVISION
,
2014 TABLE_GENERATOR_CREATOR_ID_ARM
,
2016 IORT_GENERATOR_REVISION
,
2017 // Build Table function
2019 // Free Resource function
2020 FreeIortTableResources
,
2021 // Extended build function not needed
2023 // Extended build function not implemented by the generator.
2024 // Hence extended free resource function is not required.
2028 // IORT Generator private data
2032 // Pointer to Iort node indexer
2036 /** Register the Generator with the ACPI Table Factory.
2038 @param [in] ImageHandle The handle to the image.
2039 @param [in] SystemTable Pointer to the System Table.
2041 @retval EFI_SUCCESS The Generator is registered.
2042 @retval EFI_INVALID_PARAMETER A parameter is invalid.
2043 @retval EFI_ALREADY_STARTED The Generator for the Table ID
2044 is already registered.
2048 AcpiIortLibConstructor (
2049 IN CONST EFI_HANDLE ImageHandle
,
2050 IN EFI_SYSTEM_TABLE
* CONST SystemTable
2054 Status
= RegisterAcpiTableGenerator (&IortGenerator
.Header
);
2055 DEBUG ((DEBUG_INFO
, "IORT: Register Generator. Status = %r\n", Status
));
2056 ASSERT_EFI_ERROR (Status
);
2060 /** Deregister the Generator from the ACPI Table Factory.
2062 @param [in] ImageHandle The handle to the image.
2063 @param [in] SystemTable Pointer to the System Table.
2065 @retval EFI_SUCCESS The Generator is deregistered.
2066 @retval EFI_INVALID_PARAMETER A parameter is invalid.
2067 @retval EFI_NOT_FOUND The Generator is not registered.
2071 AcpiIortLibDestructor (
2072 IN CONST EFI_HANDLE ImageHandle
,
2073 IN EFI_SYSTEM_TABLE
* CONST SystemTable
2077 Status
= DeregisterAcpiTableGenerator (&IortGenerator
.Header
);
2078 DEBUG ((DEBUG_INFO
, "Iort: Deregister Generator. Status = %r\n", Status
));
2079 ASSERT_EFI_ERROR (Status
);