]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c
DynamicTablesPkg: IORT: Fix uninitialized memory usage
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiIortLibArm / IortGenerator.c
1 /** @file
2 IORT Table Generator
3
4 Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 @par Reference(s):
8 - IO Remapping Table, Platform Design Document,
9 Document number: ARM DEN 0049D, Issue D, March 2018
10
11 **/
12
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>
19
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>
26
27 #include "IortGenerator.h"
28
29 /** ARM standard IORT Generator
30
31 Requirements:
32 The following Configuration Manager Object(s) are required by
33 this Generator:
34 - EArmObjItsGroup
35 - EArmObjNamedComponent
36 - EArmObjRootComplex
37 - EArmObjSmmuV1SmmuV2
38 - EArmObjSmmuV3
39 - EArmObjPmcg
40 - EArmObjGicItsIdentifierArray
41 - EArmObjIdMappingArray
42 - EArmObjGicItsIdentifierArray
43 */
44
45 /** This macro expands to a function that retrieves the ITS
46 Group node information from the Configuration Manager.
47 */
48 GET_OBJECT_LIST (
49 EObjNameSpaceArm,
50 EArmObjItsGroup,
51 CM_ARM_ITS_GROUP_NODE
52 );
53
54 /** This macro expands to a function that retrieves the
55 Named Component node information from the Configuration Manager.
56 */
57 GET_OBJECT_LIST (
58 EObjNameSpaceArm,
59 EArmObjNamedComponent,
60 CM_ARM_NAMED_COMPONENT_NODE
61 );
62
63 /** This macro expands to a function that retrieves the
64 Root Complex node information from the Configuration Manager.
65 */
66 GET_OBJECT_LIST (
67 EObjNameSpaceArm,
68 EArmObjRootComplex,
69 CM_ARM_ROOT_COMPLEX_NODE
70 );
71
72 /** This macro expands to a function that retrieves the
73 SMMU v1/v2 node information from the Configuration Manager.
74 */
75 GET_OBJECT_LIST (
76 EObjNameSpaceArm,
77 EArmObjSmmuV1SmmuV2,
78 CM_ARM_SMMUV1_SMMUV2_NODE
79 );
80
81 /** This macro expands to a function that retrieves the
82 SMMU v3 node information from the Configuration Manager.
83 */
84 GET_OBJECT_LIST (
85 EObjNameSpaceArm,
86 EArmObjSmmuV3,
87 CM_ARM_SMMUV3_NODE
88 );
89
90 /** This macro expands to a function that retrieves the
91 PMCG node information from the Configuration Manager.
92 */
93 GET_OBJECT_LIST (
94 EObjNameSpaceArm,
95 EArmObjPmcg,
96 CM_ARM_PMCG_NODE
97 );
98
99 /** This macro expands to a function that retrieves the
100 ITS Identifier Array information from the Configuration Manager.
101 */
102 GET_OBJECT_LIST (
103 EObjNameSpaceArm,
104 EArmObjGicItsIdentifierArray,
105 CM_ARM_ITS_IDENTIFIER
106 );
107
108 /** This macro expands to a function that retrieves the
109 Id Mapping Array information from the Configuration Manager.
110 */
111 GET_OBJECT_LIST (
112 EObjNameSpaceArm,
113 EArmObjIdMappingArray,
114 CM_ARM_ID_MAPPING
115 );
116
117 /** This macro expands to a function that retrieves the
118 SMMU Interrupt Array information from the Configuration Manager.
119 */
120 GET_OBJECT_LIST (
121 EObjNameSpaceArm,
122 EArmObjSmmuInterruptArray,
123 CM_ARM_SMMU_INTERRUPT
124 );
125
126 /** Returns the size of the ITS Group node.
127
128 @param [in] Node Pointer to ITS Group node.
129
130 @retval Size of the ITS Group Node.
131 **/
132 STATIC
133 UINT32
134 GetItsGroupNodeSize (
135 IN CONST CM_ARM_ITS_GROUP_NODE * Node
136 )
137 {
138 ASSERT (Node != NULL);
139
140 /* Size of ITS Group Node +
141 Size of ITS Identifier array
142 */
143 return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE) +
144 (Node->ItsIdCount * sizeof (UINT32)));
145 }
146
147 /** Returns the total size required for the ITS Group nodes and
148 updates the Node Indexer.
149
150 This function calculates the size required for the node group
151 and also populates the Node Indexer array with offsets for the
152 individual nodes.
153
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.
159
160 @retval Total size of the ITS Group Nodes.
161 **/
162 STATIC
163 UINT64
164 GetSizeofItsGroupNodes (
165 IN CONST UINT32 NodeStartOffset,
166 IN CONST CM_ARM_ITS_GROUP_NODE * NodeList,
167 IN UINT32 NodeCount,
168 IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
169 )
170 {
171 UINT64 Size;
172
173 ASSERT (NodeList != NULL);
174
175 Size = 0;
176 while (NodeCount-- != 0) {
177 (*NodeIndexer)->Token = NodeList->Token;
178 (*NodeIndexer)->Object = (VOID*)NodeList;
179 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
180 DEBUG ((
181 DEBUG_INFO,
182 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
183 *NodeIndexer,
184 (*NodeIndexer)->Token,
185 (*NodeIndexer)->Object,
186 (*NodeIndexer)->Offset
187 ));
188
189 Size += GetItsGroupNodeSize (NodeList);
190 (*NodeIndexer)++;
191 NodeList++;
192 }
193 return Size;
194 }
195
196 /** Returns the size of the Named Component node.
197
198 @param [in] Node Pointer to Named Component node.
199
200 @retval Size of the Named Component node.
201 **/
202 STATIC
203 UINT32
204 GetNamedComponentNodeSize (
205 IN CONST CM_ARM_NAMED_COMPONENT_NODE * Node
206 )
207 {
208 ASSERT (Node != NULL);
209
210 /* Size of Named Component node +
211 Size of ID mapping array +
212 Size of ASCII string + 'padding to 32-bit word aligned'.
213 */
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));
218 }
219
220 /** Returns the total size required for the Named Component nodes and
221 updates the Node Indexer.
222
223 This function calculates the size required for the node group
224 and also populates the Node Indexer array with offsets for the
225 individual nodes.
226
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.
232
233 @retval Total size of the Named Component nodes.
234 **/
235 STATIC
236 UINT64
237 GetSizeofNamedComponentNodes (
238 IN CONST UINT32 NodeStartOffset,
239 IN CONST CM_ARM_NAMED_COMPONENT_NODE * NodeList,
240 IN UINT32 NodeCount,
241 IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
242 )
243 {
244 UINT64 Size;
245
246 ASSERT (NodeList != NULL);
247
248 Size = 0;
249 while (NodeCount-- != 0) {
250 (*NodeIndexer)->Token = NodeList->Token;
251 (*NodeIndexer)->Object = (VOID*)NodeList;
252 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
253 DEBUG ((
254 DEBUG_INFO,
255 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
256 *NodeIndexer,
257 (*NodeIndexer)->Token,
258 (*NodeIndexer)->Object,
259 (*NodeIndexer)->Offset
260 ));
261
262 Size += GetNamedComponentNodeSize (NodeList);
263 (*NodeIndexer)++;
264 NodeList++;
265 }
266
267 return Size;
268 }
269
270 /** Returns the size of the Root Complex node.
271
272 @param [in] Node Pointer to Root Complex node.
273
274 @retval Size of the Root Complex node.
275 **/
276 STATIC
277 UINT32
278 GetRootComplexNodeSize (
279 IN CONST CM_ARM_ROOT_COMPLEX_NODE * Node
280 )
281 {
282 ASSERT (Node != NULL);
283
284 /* Size of Root Complex node +
285 Size of ID mapping array
286 */
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)));
290 }
291
292 /** Returns the total size required for the Root Complex nodes and
293 updates the Node Indexer.
294
295 This function calculates the size required for the node group
296 and also populates the Node Indexer array with offsets for the
297 individual nodes.
298
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.
304
305 @retval Total size of the Root Complex nodes.
306 **/
307 STATIC
308 UINT64
309 GetSizeofRootComplexNodes (
310 IN CONST UINT32 NodeStartOffset,
311 IN CONST CM_ARM_ROOT_COMPLEX_NODE * NodeList,
312 IN UINT32 NodeCount,
313 IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
314 )
315 {
316 UINT64 Size;
317
318 ASSERT (NodeList != NULL);
319
320 Size = 0;
321 while (NodeCount-- != 0) {
322 (*NodeIndexer)->Token = NodeList->Token;
323 (*NodeIndexer)->Object = (VOID*)NodeList;
324 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
325 DEBUG ((
326 DEBUG_INFO,
327 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
328 *NodeIndexer,
329 (*NodeIndexer)->Token,
330 (*NodeIndexer)->Object,
331 (*NodeIndexer)->Offset
332 ));
333
334 Size += GetRootComplexNodeSize (NodeList);
335 (*NodeIndexer)++;
336 NodeList++;
337 }
338
339 return Size;
340 }
341
342 /** Returns the size of the SMMUv1/SMMUv2 node.
343
344 @param [in] Node Pointer to SMMUv1/SMMUv2 node list.
345
346 @retval Size of the SMMUv1/SMMUv2 node.
347 **/
348 STATIC
349 UINT32
350 GetSmmuV1V2NodeSize (
351 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE * Node
352 )
353 {
354 ASSERT (Node != NULL);
355
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
360 */
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)));
368 }
369
370 /** Returns the total size required for the SMMUv1/SMMUv2 nodes and
371 updates the Node Indexer.
372
373 This function calculates the size required for the node group
374 and also populates the Node Indexer array with offsets for the
375 individual nodes.
376
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.
382
383 @retval Total size of the SMMUv1/SMMUv2 nodes.
384 **/
385 STATIC
386 UINT64
387 GetSizeofSmmuV1V2Nodes (
388 IN CONST UINT32 NodeStartOffset,
389 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE * NodeList,
390 IN UINT32 NodeCount,
391 IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
392 )
393 {
394 UINT64 Size;
395
396 ASSERT (NodeList != NULL);
397
398 Size = 0;
399 while (NodeCount-- != 0) {
400 (*NodeIndexer)->Token = NodeList->Token;
401 (*NodeIndexer)->Object = (VOID*)NodeList;
402 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
403 DEBUG ((
404 DEBUG_INFO,
405 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
406 *NodeIndexer,
407 (*NodeIndexer)->Token,
408 (*NodeIndexer)->Object,
409 (*NodeIndexer)->Offset
410 ));
411
412 Size += GetSmmuV1V2NodeSize (NodeList);
413 (*NodeIndexer)++;
414 NodeList++;
415 }
416 return Size;
417 }
418
419 /** Returns the size of the SMMUv3 node.
420
421 @param [in] Node Pointer to SMMUv3 node list.
422
423 @retval Total size of the SMMUv3 nodes.
424 **/
425 STATIC
426 UINT32
427 GetSmmuV3NodeSize (
428 IN CONST CM_ARM_SMMUV3_NODE * Node
429 )
430 {
431 ASSERT (Node != NULL);
432
433 /* Size of SMMU v1/SMMU v2 node +
434 Size of ID mapping array
435 */
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)));
439 }
440
441 /** Returns the total size required for the SMMUv3 nodes and
442 updates the Node Indexer.
443
444 This function calculates the size required for the node group
445 and also populates the Node Indexer array with offsets for the
446 individual nodes.
447
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.
453
454 @retval Total size of the SMMUv3 nodes.
455 **/
456 STATIC
457 UINT64
458 GetSizeofSmmuV3Nodes (
459 IN CONST UINT32 NodeStartOffset,
460 IN CONST CM_ARM_SMMUV3_NODE * NodeList,
461 IN UINT32 NodeCount,
462 IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
463 )
464 {
465 UINT64 Size;
466
467 ASSERT (NodeList != NULL);
468
469 Size = 0;
470 while (NodeCount-- != 0) {
471 (*NodeIndexer)->Token = NodeList->Token;
472 (*NodeIndexer)->Object = (VOID*)NodeList;
473 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
474 DEBUG ((
475 DEBUG_INFO,
476 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
477 *NodeIndexer,
478 (*NodeIndexer)->Token,
479 (*NodeIndexer)->Object,
480 (*NodeIndexer)->Offset
481 ));
482
483 Size += GetSmmuV3NodeSize (NodeList);
484 (*NodeIndexer)++;
485 NodeList++;
486 }
487 return Size;
488 }
489
490 /** Returns the size of the PMCG node.
491
492 @param [in] Node Pointer to PMCG node.
493
494 @retval Size of the PMCG node.
495 **/
496 STATIC
497 UINT32
498 GetPmcgNodeSize (
499 IN CONST CM_ARM_PMCG_NODE * Node
500 )
501 {
502 ASSERT (Node != NULL);
503
504 /* Size of PMCG node +
505 Size of ID mapping array
506 */
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)));
510 }
511
512 /** Returns the total size required for the PMCG nodes and
513 updates the Node Indexer.
514
515 This function calculates the size required for the node group
516 and also populates the Node Indexer array with offsets for the
517 individual nodes.
518
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.
524
525 @retval Total size of the PMCG nodes.
526 **/
527 STATIC
528 UINT64
529 GetSizeofPmcgNodes (
530 IN CONST UINT32 NodeStartOffset,
531 IN CONST CM_ARM_PMCG_NODE * NodeList,
532 IN UINT32 NodeCount,
533 IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
534 )
535 {
536 UINT64 Size;
537
538 ASSERT (NodeList != NULL);
539
540 Size = 0;
541 while (NodeCount-- != 0) {
542 (*NodeIndexer)->Token = NodeList->Token;
543 (*NodeIndexer)->Object = (VOID*)NodeList;
544 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
545 DEBUG ((
546 DEBUG_INFO,
547 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
548 *NodeIndexer,
549 (*NodeIndexer)->Token,
550 (*NodeIndexer)->Object,
551 (*NodeIndexer)->Offset
552 ));
553
554 Size += GetPmcgNodeSize (NodeList);
555 (*NodeIndexer)++;
556 NodeList++;
557 }
558 return Size;
559 }
560
561 /** Returns the offset of the Node referenced by the Token.
562
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.
568
569 @retval EFI_SUCCESS Success.
570 @retval EFI_NOT_FOUND No matching token reference
571 found in node indexer array.
572 **/
573 STATIC
574 EFI_STATUS
575 GetNodeOffsetReferencedByToken (
576 IN IORT_NODE_INDEXER * NodeIndexer,
577 IN UINT32 NodeCount,
578 IN CM_OBJECT_TOKEN Token,
579 OUT UINT32 * NodeOffset
580 )
581 {
582 DEBUG ((
583 DEBUG_INFO,
584 "IORT: Node Indexer: Search Token = %p\n",
585 Token
586 ));
587 while (NodeCount-- != 0) {
588 DEBUG ((
589 DEBUG_INFO,
590 "IORT: Node Indexer: NodeIndexer->Token = %p, Offset = %d\n",
591 NodeIndexer->Token,
592 NodeIndexer->Offset
593 ));
594 if (NodeIndexer->Token == Token) {
595 *NodeOffset = NodeIndexer->Offset;
596 DEBUG ((
597 DEBUG_INFO,
598 "IORT: Node Indexer: Token = %p, Found\n",
599 Token
600 ));
601 return EFI_SUCCESS;
602 }
603 NodeIndexer++;
604 }
605 DEBUG ((
606 DEBUG_INFO,
607 "IORT: Node Indexer: Token = %p, Not Found\n",
608 Token
609 ));
610 return EFI_NOT_FOUND;
611 }
612
613 /** Update the Id Mapping Array.
614
615 This function retrieves the Id Mapping Array object referenced by the
616 IdMappingToken and updates the IdMapArray.
617
618 @param [in] This Pointer to the table Generator.
619 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
620 Protocol Interface.
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.
625
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.
629 **/
630 STATIC
631 EFI_STATUS
632 AddIdMappingArray (
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,
636 IN UINT32 IdCount,
637 IN CONST CM_OBJECT_TOKEN IdMappingToken
638 )
639 {
640 EFI_STATUS Status;
641 CM_ARM_ID_MAPPING * IdMappings;
642 UINT32 IdMappingCount;
643 ACPI_IORT_GENERATOR * Generator;
644
645 ASSERT (IdMapArray != NULL);
646
647 Generator = (ACPI_IORT_GENERATOR*)This;
648
649 // Get the Id Mapping Array
650 Status = GetEArmObjIdMappingArray (
651 CfgMgrProtocol,
652 IdMappingToken,
653 &IdMappings,
654 &IdMappingCount
655 );
656 if (EFI_ERROR (Status)) {
657 DEBUG ((
658 DEBUG_ERROR,
659 "ERROR: IORT: Failed to get Id Mapping array. Status = %r\n",
660 Status
661 ));
662 return Status;
663 }
664
665 if (IdMappingCount < IdCount) {
666 DEBUG ((
667 DEBUG_ERROR,
668 "ERROR: IORT: Failed to get the required number of Id Mappings.\n"
669 ));
670 return EFI_NOT_FOUND;
671 }
672
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
680 );
681 if (EFI_ERROR (Status)) {
682 DEBUG ((
683 DEBUG_ERROR,
684 "ERROR: IORT: Failed to get Output Reference for ITS Identifier array."
685 "Reference Token = %p"
686 " Status = %r\n",
687 IdMappings->OutputReferenceToken,
688 Status
689 ));
690 return Status;
691 }
692
693 IdMapArray->InputBase = IdMappings->InputBase;
694 IdMapArray->NumIds = IdMappings->NumIds;
695 IdMapArray->OutputBase = IdMappings->OutputBase;
696 IdMapArray->Flags = IdMappings->Flags;
697
698 IdMapArray++;
699 IdMappings++;
700 } // Id Mapping array
701
702 return EFI_SUCCESS;
703 }
704
705 /** Update the ITS Group Node Information.
706
707 @param [in] This Pointer to the table Generator.
708 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
709 Protocol Interface.
710 @param [in] Iort Pointer to IORT table structure.
711 @param [in] NodesStartOffset Offset for the start of the ITS Group
712 Nodes.
713 @param [in] NodeList Pointer to an array of ITS Group Node
714 Objects.
715 @param [in] NodeCount Number of ITS Group Node Objects.
716
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.
720 **/
721 STATIC
722 EFI_STATUS
723 AddItsGroupNodes (
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,
729 IN UINT32 NodeCount
730 )
731 {
732 EFI_STATUS Status;
733 EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE * ItsGroupNode;
734 UINT32 * ItsIds;
735 CM_ARM_ITS_IDENTIFIER * ItsIdentifier;
736 UINT32 ItsIdentifierCount;
737 UINT32 IdIndex;
738 UINT64 NodeLength;
739
740 ASSERT (Iort != NULL);
741
742 ItsGroupNode = (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE*)((UINT8*)Iort +
743 NodesStartOffset);
744
745 while (NodeCount-- != 0) {
746 NodeLength = GetItsGroupNodeSize (NodeList);
747 if (NodeLength > MAX_UINT16) {
748 Status = EFI_INVALID_PARAMETER;
749 DEBUG ((
750 DEBUG_ERROR,
751 "ERROR: IORT: ITS Id Array Node length 0x%lx > MAX_UINT16."
752 " Status = %r\n",
753 NodeLength,
754 Status
755 ));
756 return Status;
757 }
758
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;
766
767 // IORT specific data
768 ItsGroupNode->NumItsIdentifiers = NodeList->ItsIdCount;
769 ItsIds = (UINT32*)((UINT8*)ItsGroupNode +
770 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE));
771
772 Status = GetEArmObjGicItsIdentifierArray (
773 CfgMgrProtocol,
774 NodeList->ItsIdToken,
775 &ItsIdentifier,
776 &ItsIdentifierCount
777 );
778 if (EFI_ERROR (Status)) {
779 DEBUG ((
780 DEBUG_ERROR,
781 "ERROR: IORT: Failed to get ITS Identifier array. Status = %r\n",
782 Status
783 ));
784 return Status;
785 }
786
787 if (ItsIdentifierCount < ItsGroupNode->NumItsIdentifiers) {
788 DEBUG ((
789 DEBUG_ERROR,
790 "ERROR: IORT: Failed to get the required number of ITS Identifiers.\n"
791 ));
792 return EFI_NOT_FOUND;
793 }
794
795 // Populate the ITS identifier array
796 for (IdIndex = 0; IdIndex < ItsGroupNode->NumItsIdentifiers; IdIndex++) {
797 ItsIds[IdIndex] = ItsIdentifier[IdIndex].ItsId;
798 } // ITS identifier array
799
800 // Next IORT Group Node
801 ItsGroupNode = (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE*)((UINT8*)ItsGroupNode +
802 ItsGroupNode->Node.Length);
803 NodeList++;
804 } // IORT Group Node
805
806 return EFI_SUCCESS;
807 }
808
809 /** Update the Named Component Node Information.
810
811 This function updates the Named Component node information in the IORT
812 table.
813
814 @param [in] This Pointer to the table Generator.
815 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
816 Protocol Interface.
817 @param [in] Iort Pointer to IORT table structure.
818 @param [in] NodesStartOffset Offset for the start of the Named
819 Component Nodes.
820 @param [in] NodeList Pointer to an array of Named Component
821 Node Objects.
822 @param [in] NodeCount Number of Named Component Node Objects.
823
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.
827 **/
828 STATIC
829 EFI_STATUS
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,
836 IN UINT32 NodeCount
837 )
838 {
839 EFI_STATUS Status;
840 EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE * NcNode;
841 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;
842 CHAR8 * ObjectName;
843 UINTN ObjectNameLength;
844 UINT64 NodeLength;
845
846 ASSERT (Iort != NULL);
847
848 NcNode = (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE*)((UINT8*)Iort +
849 NodesStartOffset);
850
851 while (NodeCount-- != 0) {
852 NodeLength = GetNamedComponentNodeSize (NodeList);
853 if (NodeLength > MAX_UINT16) {
854 Status = EFI_INVALID_PARAMETER;
855 DEBUG ((
856 DEBUG_ERROR,
857 "ERROR: IORT: Named Component Node length 0x%lx > MAX_UINT16."
858 " Status = %r\n",
859 NodeLength,
860 Status
861 ));
862 return Status;
863 }
864
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;
871
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)));
876
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;
884
885 // Copy the object name
886 ObjectName = (CHAR8*)((UINT8*)NcNode +
887 sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE));
888 Status = AsciiStrCpyS (
889 ObjectName,
890 ObjectNameLength,
891 NodeList->ObjectName
892 );
893 if (EFI_ERROR (Status)) {
894 DEBUG ((
895 DEBUG_ERROR,
896 "ERROR: IORT: Failed to copy Object Name. Status = %r\n",
897 Status
898 ));
899 return Status;
900 }
901
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);
907
908 Status = AddIdMappingArray (
909 This,
910 CfgMgrProtocol,
911 IdMapArray,
912 NodeList->IdMappingCount,
913 NodeList->IdMappingToken
914 );
915 if (EFI_ERROR (Status)) {
916 DEBUG ((
917 DEBUG_ERROR,
918 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
919 Status
920 ));
921 return Status;
922 }
923 }
924
925 // Next Named Component Node
926 NcNode = (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE*)((UINT8*)NcNode +
927 NcNode->Node.Length);
928 NodeList++;
929 } // Named Component Node
930
931 return EFI_SUCCESS;
932 }
933
934 /** Update the Root Complex Node Information.
935
936 This function updates the Root Complex node information in the IORT table.
937
938 @param [in] This Pointer to the table Generator.
939 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
940 Protocol Interface.
941 @param [in] Iort Pointer to IORT table structure.
942 @param [in] NodesStartOffset Offset for the start of the Root Complex
943 Nodes.
944 @param [in] NodeList Pointer to an array of Root Complex Node
945 Objects.
946 @param [in] NodeCount Number of Root Complex Node Objects.
947
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.
951 **/
952 STATIC
953 EFI_STATUS
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,
960 IN UINT32 NodeCount
961 )
962 {
963 EFI_STATUS Status;
964 EFI_ACPI_6_0_IO_REMAPPING_RC_NODE * RcNode;
965 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;
966 UINT64 NodeLength;
967
968 ASSERT (Iort != NULL);
969
970 RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE*)((UINT8*)Iort +
971 NodesStartOffset);
972
973 while (NodeCount-- != 0) {
974 NodeLength = GetRootComplexNodeSize (NodeList);
975 if (NodeLength > MAX_UINT16) {
976 Status = EFI_INVALID_PARAMETER;
977 DEBUG ((
978 DEBUG_ERROR,
979 "ERROR: IORT: Root Complex Node length 0x%lx > MAX_UINT16."
980 " Status = %r\n",
981 NodeLength,
982 Status
983 ));
984 return Status;
985 }
986
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);
994
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;
1006
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 (
1013 This,
1014 CfgMgrProtocol,
1015 IdMapArray,
1016 NodeList->IdMappingCount,
1017 NodeList->IdMappingToken
1018 );
1019 if (EFI_ERROR (Status)) {
1020 DEBUG ((
1021 DEBUG_ERROR,
1022 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1023 Status
1024 ));
1025 return Status;
1026 }
1027 }
1028
1029 // Next Root Complex Node
1030 RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE*)((UINT8*)RcNode +
1031 RcNode->Node.Length);
1032 NodeList++;
1033 } // Root Complex Node
1034
1035 return EFI_SUCCESS;
1036 }
1037
1038 /** Update the SMMU Interrupt Array.
1039
1040 This function retrieves the InterruptArray object referenced by the
1041 InterruptToken and updates the SMMU InterruptArray.
1042
1043 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1044 Protocol Interface.
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.
1049
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.
1053 **/
1054 STATIC
1055 EFI_STATUS
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
1061 )
1062 {
1063 EFI_STATUS Status;
1064 CM_ARM_SMMU_INTERRUPT * SmmuInterrupt;
1065 UINT32 SmmuInterruptCount;
1066
1067 ASSERT (InterruptArray != NULL);
1068
1069 // Get the SMMU Interrupt Array
1070 Status = GetEArmObjSmmuInterruptArray (
1071 CfgMgrProtocol,
1072 InterruptToken,
1073 &SmmuInterrupt,
1074 &SmmuInterruptCount
1075 );
1076 if (EFI_ERROR (Status)) {
1077 DEBUG ((
1078 DEBUG_ERROR,
1079 "ERROR: IORT: Failed to get SMMU Interrupt array. Status = %r\n",
1080 Status
1081 ));
1082 return Status;
1083 }
1084
1085 if (SmmuInterruptCount < InterruptCount) {
1086 DEBUG ((
1087 DEBUG_ERROR,
1088 "ERROR: IORT: Failed to get the required number of SMMU Interrupts.\n"
1089 ));
1090 return EFI_NOT_FOUND;
1091 }
1092
1093 // Populate the Id Mapping array
1094 while (InterruptCount-- != 0) {
1095 InterruptArray->Interrupt = SmmuInterrupt->Interrupt;
1096 InterruptArray->InterruptFlags = SmmuInterrupt->Flags;
1097 InterruptArray++;
1098 SmmuInterrupt++;
1099 } // Id Mapping array
1100
1101 return EFI_SUCCESS;
1102 }
1103
1104 /** Update the SMMU v1/v2 Node Information.
1105
1106 @param [in] This Pointer to the table Generator.
1107 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1108 Protocol Interface.
1109 @param [in] Iort Pointer to IORT table structure.
1110 @param [in] NodesStartOffset Offset for the start of the SMMU v1/v2
1111 Nodes.
1112 @param [in] NodeList Pointer to an array of SMMU v1/v2 Node
1113 Objects.
1114 @param [in] NodeCount Number of SMMU v1/v2 Node Objects.
1115
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.
1119 **/
1120 STATIC
1121 EFI_STATUS
1122 AddSmmuV1V2Nodes (
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,
1128 IN UINT32 NodeCount
1129 )
1130 {
1131 EFI_STATUS Status;
1132 EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE * SmmuNode;
1133 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;
1134
1135 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT * ContextInterruptArray;
1136 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT * PmuInterruptArray;
1137 UINT64 NodeLength;
1138
1139 ASSERT (Iort != NULL);
1140
1141 SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE*)((UINT8*)Iort +
1142 NodesStartOffset);
1143
1144 while (NodeCount-- != 0) {
1145 NodeLength = GetSmmuV1V2NodeSize (NodeList);
1146 if (NodeLength > MAX_UINT16) {
1147 Status = EFI_INVALID_PARAMETER;
1148 DEBUG ((
1149 DEBUG_ERROR,
1150 "ERROR: IORT: SMMU V1/V2 Node length 0x%lx > MAX_UINT16. Status = %r\n",
1151 NodeLength,
1152 Status
1153 ));
1154 return Status;
1155 }
1156
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));
1168
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;
1174
1175 // Reference to Global Interrupt Array
1176 SmmuNode->GlobalInterruptArrayRef =
1177 OFFSET_OF (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE, SMMU_NSgIrpt);
1178
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));
1186
1187 // PMU Interrupt
1188 SmmuNode->NumPmuInterrupts = NodeList->PmuInterruptCount;
1189 SmmuNode->PmuInterruptArrayRef = SmmuNode->ContextInterruptArrayRef +
1190 (NodeList->ContextInterruptCount *
1191 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));
1192 PmuInterruptArray =
1193 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT*)((UINT8*)SmmuNode +
1194 SmmuNode->PmuInterruptArrayRef);
1195
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;
1200
1201 // Add Context Interrupt Array
1202 Status = AddSmmuInterrruptArray (
1203 CfgMgrProtocol,
1204 ContextInterruptArray,
1205 SmmuNode->NumContextInterrupts,
1206 NodeList->ContextInterruptToken
1207 );
1208 if (EFI_ERROR (Status)) {
1209 DEBUG ((
1210 DEBUG_ERROR,
1211 "ERROR: IORT: Failed to Context Interrupt Array. Status = %r\n",
1212 Status
1213 ));
1214 return Status;
1215 }
1216
1217 // Add PMU Interrupt Array
1218 if ((SmmuNode->NumPmuInterrupts > 0) &&
1219 (NodeList->PmuInterruptToken != CM_NULL_TOKEN)) {
1220 Status = AddSmmuInterrruptArray (
1221 CfgMgrProtocol,
1222 PmuInterruptArray,
1223 SmmuNode->NumPmuInterrupts,
1224 NodeList->PmuInterruptToken
1225 );
1226 if (EFI_ERROR (Status)) {
1227 DEBUG ((
1228 DEBUG_ERROR,
1229 "ERROR: IORT: Failed to PMU Interrupt Array. Status = %r\n",
1230 Status
1231 ));
1232 return Status;
1233 }
1234 }
1235
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 (
1242 This,
1243 CfgMgrProtocol,
1244 IdMapArray,
1245 NodeList->IdMappingCount,
1246 NodeList->IdMappingToken
1247 );
1248 if (EFI_ERROR (Status)) {
1249 DEBUG ((
1250 DEBUG_ERROR,
1251 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1252 Status
1253 ));
1254 return Status;
1255 }
1256 }
1257 // Next SMMU v1/v2 Node
1258 SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE*)((UINT8*)SmmuNode +
1259 SmmuNode->Node.Length);
1260 NodeList++;
1261 } // SMMU v1/v2 Node
1262
1263 return EFI_SUCCESS;
1264 }
1265
1266 /** Update the SMMUv3 Node Information.
1267
1268 This function updates the SMMUv3 node information in the IORT table.
1269
1270 @param [in] This Pointer to the table Generator.
1271 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1272 Protocol Interface.
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.
1277
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.
1281 **/
1282 STATIC
1283 EFI_STATUS
1284 AddSmmuV3Nodes (
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,
1290 IN UINT32 NodeCount
1291 )
1292 {
1293 EFI_STATUS Status;
1294 EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE * SmmuV3Node;
1295 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;
1296 UINT64 NodeLength;
1297
1298 ASSERT (Iort != NULL);
1299
1300 SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE*)((UINT8*)Iort +
1301 NodesStartOffset);
1302
1303 while (NodeCount-- != 0) {
1304 NodeLength = GetSmmuV3NodeSize (NodeList);
1305 if (NodeLength > MAX_UINT16) {
1306 Status = EFI_INVALID_PARAMETER;
1307 DEBUG ((
1308 DEBUG_ERROR,
1309 "ERROR: IORT: SMMU V3 Node length 0x%lx > MAX_UINT16. Status = %r\n",
1310 NodeLength,
1311 Status
1312 ));
1313 return Status;
1314 }
1315
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);
1324
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;
1335
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;
1339 } else {
1340 SmmuV3Node->ProximityDomain = 0;
1341 }
1342
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;
1348 } else {
1349 SmmuV3Node->DeviceIdMappingIndex = NodeList->DeviceIdMappingIndex;
1350 }
1351
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 (
1358 This,
1359 CfgMgrProtocol,
1360 IdMapArray,
1361 NodeList->IdMappingCount,
1362 NodeList->IdMappingToken
1363 );
1364 if (EFI_ERROR (Status)) {
1365 DEBUG ((
1366 DEBUG_ERROR,
1367 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1368 Status
1369 ));
1370 return Status;
1371 }
1372 }
1373
1374 // Next SMMUv3 Node
1375 SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE*)((UINT8*)SmmuV3Node +
1376 SmmuV3Node->Node.Length);
1377 NodeList++;
1378 } // SMMUv3 Node
1379
1380 return EFI_SUCCESS;
1381 }
1382
1383 /** Update the PMCG Node Information.
1384
1385 This function updates the PMCG node information in the IORT table.
1386
1387 @param [in] This Pointer to the table Generator.
1388 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1389 Protocol Interface.
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.
1394
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.
1398 **/
1399 STATIC
1400 EFI_STATUS
1401 AddPmcgNodes (
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,
1407 IN UINT32 NodeCount
1408 )
1409 {
1410 EFI_STATUS Status;
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;
1414 UINT64 NodeLength;
1415
1416 ASSERT (Iort != NULL);
1417
1418 Generator = (ACPI_IORT_GENERATOR*)This;
1419 PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE*)((UINT8*)Iort +
1420 NodesStartOffset);
1421
1422 while (NodeCount-- != 0) {
1423 NodeLength = GetPmcgNodeSize (NodeList);
1424 if (NodeLength > MAX_UINT16) {
1425 Status = EFI_INVALID_PARAMETER;
1426 DEBUG ((
1427 DEBUG_ERROR,
1428 "ERROR: IORT: PMCG Node length 0x%lx > MAX_UINT16. Status = %r\n",
1429 NodeLength,
1430 Status
1431 ));
1432 return Status;
1433 }
1434
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);
1442
1443 // PMCG specific data
1444 PmcgNode->Base = NodeList->BaseAddress;
1445 PmcgNode->OverflowInterruptGsiv = NodeList->OverflowInterrupt;
1446 PmcgNode->Page1Base = NodeList->Page1BaseAddress;
1447
1448 Status = GetNodeOffsetReferencedByToken (
1449 Generator->NodeIndexer,
1450 Generator->IortNodeCount,
1451 NodeList->ReferenceToken,
1452 &PmcgNode->NodeReference
1453 );
1454 if (EFI_ERROR (Status)) {
1455 DEBUG ((
1456 DEBUG_ERROR,
1457 "ERROR: IORT: Failed to get Output Reference for PMCG Node."
1458 "Reference Token = %p"
1459 " Status = %r\n",
1460 NodeList->ReferenceToken,
1461 Status
1462 ));
1463 return Status;
1464 }
1465
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);
1471
1472 Status = AddIdMappingArray (
1473 This,
1474 CfgMgrProtocol,
1475 IdMapArray,
1476 NodeList->IdMappingCount,
1477 NodeList->IdMappingToken
1478 );
1479 if (EFI_ERROR (Status)) {
1480 DEBUG ((
1481 DEBUG_ERROR,
1482 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1483 Status
1484 ));
1485 return Status;
1486 }
1487 }
1488
1489 // Next PMCG Node
1490 PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE*)((UINT8*)PmcgNode +
1491 PmcgNode->Node.Length);
1492 NodeList++;
1493 } // PMCG Node
1494
1495 return EFI_SUCCESS;
1496 }
1497
1498 /** Construct the IORT ACPI table.
1499
1500 This function invokes the Configuration Manager protocol interface
1501 to get the required hardware information for generating the ACPI
1502 table.
1503
1504 If this function allocates any resources then they must be freed
1505 in the FreeXXXXTableResources function.
1506
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
1510 Protocol Interface.
1511 @param [out] Table Pointer to the constructed ACPI Table.
1512
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
1518 requested object.
1519 **/
1520 STATIC
1521 EFI_STATUS
1522 EFIAPI
1523 BuildIortTable (
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
1528 )
1529 {
1530 EFI_STATUS Status;
1531
1532 UINT64 TableSize;
1533 UINT64 NodeSize;
1534
1535 UINT32 IortNodeCount;
1536 UINT32 ItsGroupNodeCount;
1537 UINT32 NamedComponentNodeCount;
1538 UINT32 RootComplexNodeCount;
1539 UINT32 SmmuV1V2NodeCount;
1540 UINT32 SmmuV3NodeCount;
1541 UINT32 PmcgNodeCount;
1542
1543 UINT32 ItsGroupOffset;
1544 UINT32 NamedComponentOffset;
1545 UINT32 RootComplexOffset;
1546 UINT32 SmmuV1V2Offset;
1547 UINT32 SmmuV3Offset;
1548 UINT32 PmcgOffset;
1549
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;
1556
1557 EFI_ACPI_6_0_IO_REMAPPING_TABLE * Iort;
1558 IORT_NODE_INDEXER * NodeIndexer;
1559 ACPI_IORT_GENERATOR * Generator;
1560
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);
1567
1568 if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
1569 (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
1570 DEBUG ((
1571 DEBUG_ERROR,
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
1577 ));
1578 return EFI_INVALID_PARAMETER;
1579 }
1580
1581 Generator = (ACPI_IORT_GENERATOR*)This;
1582 *Table = NULL;
1583
1584 // Get the ITS group node info
1585 Status = GetEArmObjItsGroup (
1586 CfgMgrProtocol,
1587 CM_NULL_TOKEN,
1588 &ItsGroupNodeList,
1589 &ItsGroupNodeCount
1590 );
1591 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
1592 DEBUG ((
1593 DEBUG_ERROR,
1594 "ERROR: IORT: Failed to get ITS Group Node Info. Status = %r\n",
1595 Status
1596 ));
1597 goto error_handler;
1598 }
1599
1600 // Add the ITS group node count
1601 IortNodeCount = ItsGroupNodeCount;
1602
1603 // Get the Named component node info
1604 Status = GetEArmObjNamedComponent (
1605 CfgMgrProtocol,
1606 CM_NULL_TOKEN,
1607 &NamedComponentNodeList,
1608 &NamedComponentNodeCount
1609 );
1610 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
1611 DEBUG ((
1612 DEBUG_ERROR,
1613 "ERROR: IORT: Failed to get Named Component Node Info. Status = %r\n",
1614 Status
1615 ));
1616 goto error_handler;
1617 }
1618
1619 // Add the Named Component group count
1620 IortNodeCount += NamedComponentNodeCount;
1621
1622 // Get the Root complex node info
1623 Status = GetEArmObjRootComplex (
1624 CfgMgrProtocol,
1625 CM_NULL_TOKEN,
1626 &RootComplexNodeList,
1627 &RootComplexNodeCount
1628 );
1629 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
1630 DEBUG ((
1631 DEBUG_ERROR,
1632 "ERROR: IORT: Failed to get Root Complex Node Info. Status = %r\n",
1633 Status
1634 ));
1635 goto error_handler;
1636 }
1637
1638 // Add the Root Complex node count
1639 IortNodeCount += RootComplexNodeCount;
1640
1641 // Get the SMMU v1/v2 node info
1642 Status = GetEArmObjSmmuV1SmmuV2 (
1643 CfgMgrProtocol,
1644 CM_NULL_TOKEN,
1645 &SmmuV1V2NodeList,
1646 &SmmuV1V2NodeCount
1647 );
1648 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
1649 DEBUG ((
1650 DEBUG_ERROR,
1651 "ERROR: IORT: Failed to get SMMUv1/SMMUv2 Node Info. Status = %r\n",
1652 Status
1653 ));
1654 goto error_handler;
1655 }
1656
1657 // Add the SMMU v1/v2 node count
1658 IortNodeCount += SmmuV1V2NodeCount;
1659
1660 // Get the SMMUv3 node info
1661 Status = GetEArmObjSmmuV3 (
1662 CfgMgrProtocol,
1663 CM_NULL_TOKEN,
1664 &SmmuV3NodeList,
1665 &SmmuV3NodeCount
1666 );
1667 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
1668 DEBUG ((
1669 DEBUG_ERROR,
1670 "ERROR: IORT: Failed to get SMMUv3 Node Info. Status = %r\n",
1671 Status
1672 ));
1673 goto error_handler;
1674 }
1675
1676 // Add the SMMUv3 node count
1677 IortNodeCount += SmmuV3NodeCount;
1678
1679 // Get the PMCG node info
1680 Status = GetEArmObjPmcg (
1681 CfgMgrProtocol,
1682 CM_NULL_TOKEN,
1683 &PmcgNodeList,
1684 &PmcgNodeCount
1685 );
1686 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
1687 DEBUG ((
1688 DEBUG_ERROR,
1689 "ERROR: IORT: Failed to get PMCG Node Info. Status = %r\n",
1690 Status
1691 ));
1692 goto error_handler;
1693 }
1694
1695 // Add the PMCG node count
1696 IortNodeCount += PmcgNodeCount;
1697
1698 // Allocate Node Indexer array
1699 NodeIndexer = (IORT_NODE_INDEXER*)AllocateZeroPool (
1700 (sizeof (IORT_NODE_INDEXER) *
1701 IortNodeCount)
1702 );
1703 if (NodeIndexer == NULL) {
1704 Status = EFI_OUT_OF_RESOURCES;
1705 DEBUG ((
1706 DEBUG_ERROR,
1707 "ERROR: IORT: Failed to allocate memory for Node Indexer" \
1708 " Status = %r\n",
1709 Status
1710 ));
1711 goto error_handler;
1712 }
1713
1714 DEBUG ((DEBUG_INFO, "INFO: NodeIndexer = %p\n", NodeIndexer));
1715 Generator->IortNodeCount = IortNodeCount;
1716 Generator->NodeIndexer = NodeIndexer;
1717
1718 // Calculate the size of the IORT table
1719 TableSize = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);
1720
1721 // ITS Group Nodes
1722 if (ItsGroupNodeCount > 0) {
1723 ItsGroupOffset = (UINT32)TableSize;
1724 // Size of ITS Group node list.
1725 NodeSize = GetSizeofItsGroupNodes (
1726 ItsGroupOffset,
1727 ItsGroupNodeList,
1728 ItsGroupNodeCount,
1729 &NodeIndexer
1730 );
1731 if (NodeSize > MAX_UINT32) {
1732 Status = EFI_INVALID_PARAMETER;
1733 DEBUG ((
1734 DEBUG_ERROR,
1735 "ERROR: IORT: Invalid Size of Group Nodes. Status = %r\n",
1736 Status
1737 ));
1738 goto error_handler;
1739 }
1740 TableSize += NodeSize;
1741
1742 DEBUG ((
1743 DEBUG_INFO,
1744 " ItsGroupNodeCount = %d\n" \
1745 " ItsGroupOffset = %d\n",
1746 ItsGroupNodeCount,
1747 ItsGroupOffset
1748 ));
1749 }
1750
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,
1759 &NodeIndexer
1760 );
1761 if (NodeSize > MAX_UINT32) {
1762 Status = EFI_INVALID_PARAMETER;
1763 DEBUG ((
1764 DEBUG_ERROR,
1765 "ERROR: IORT: Invalid Size of Named Component Nodes. Status = %r\n",
1766 Status
1767 ));
1768 goto error_handler;
1769 }
1770 TableSize += NodeSize;
1771
1772 DEBUG ((
1773 DEBUG_INFO,
1774 " NamedComponentNodeCount = %d\n" \
1775 " NamedComponentOffset = %d\n",
1776 NamedComponentNodeCount,
1777 NamedComponentOffset
1778 ));
1779 }
1780
1781 // Root Complex Nodes
1782 if (RootComplexNodeCount > 0) {
1783 RootComplexOffset = (UINT32)TableSize;
1784 // Size of Root Complex node list.
1785 NodeSize = GetSizeofRootComplexNodes (
1786 RootComplexOffset,
1787 RootComplexNodeList,
1788 RootComplexNodeCount,
1789 &NodeIndexer
1790 );
1791 if (NodeSize > MAX_UINT32) {
1792 Status = EFI_INVALID_PARAMETER;
1793 DEBUG ((
1794 DEBUG_ERROR,
1795 "ERROR: IORT: Invalid Size of Root Complex Nodes. Status = %r\n",
1796 Status
1797 ));
1798 goto error_handler;
1799 }
1800 TableSize += NodeSize;
1801
1802 DEBUG ((
1803 DEBUG_INFO,
1804 " RootComplexNodeCount = %d\n" \
1805 " RootComplexOffset = %d\n",
1806 RootComplexNodeCount,
1807 RootComplexOffset
1808 ));
1809 }
1810
1811 // SMMUv1/SMMUv2 Nodes
1812 if (SmmuV1V2NodeCount > 0) {
1813 SmmuV1V2Offset = (UINT32)TableSize;
1814 // Size of SMMUv1/SMMUv2 node list.
1815 NodeSize = GetSizeofSmmuV1V2Nodes (
1816 SmmuV1V2Offset,
1817 SmmuV1V2NodeList,
1818 SmmuV1V2NodeCount,
1819 &NodeIndexer
1820 );
1821 if (NodeSize > MAX_UINT32) {
1822 Status = EFI_INVALID_PARAMETER;
1823 DEBUG ((
1824 DEBUG_ERROR,
1825 "ERROR: IORT: Invalid Size of SMMUv1/v2 Nodes. Status = %r\n",
1826 Status
1827 ));
1828 goto error_handler;
1829 }
1830 TableSize += NodeSize;
1831
1832 DEBUG ((
1833 DEBUG_INFO,
1834 " SmmuV1V2NodeCount = %d\n" \
1835 " SmmuV1V2Offset = %d\n",
1836 SmmuV1V2NodeCount,
1837 SmmuV1V2Offset
1838 ));
1839 }
1840
1841 // SMMUv3 Nodes
1842 if (SmmuV3NodeCount > 0) {
1843 SmmuV3Offset = (UINT32)TableSize;
1844 // Size of SMMUv3 node list.
1845 NodeSize = GetSizeofSmmuV3Nodes (
1846 SmmuV3Offset,
1847 SmmuV3NodeList,
1848 SmmuV3NodeCount,
1849 &NodeIndexer
1850 );
1851 if (NodeSize > MAX_UINT32) {
1852 Status = EFI_INVALID_PARAMETER;
1853 DEBUG ((
1854 DEBUG_ERROR,
1855 "ERROR: IORT: Invalid Size of SMMUv3 Nodes. Status = %r\n",
1856 Status
1857 ));
1858 goto error_handler;
1859 }
1860 TableSize += NodeSize;
1861
1862 DEBUG ((
1863 DEBUG_INFO,
1864 " SmmuV3NodeCount = %d\n" \
1865 " SmmuV3Offset = %d\n",
1866 SmmuV3NodeCount,
1867 SmmuV3Offset
1868 ));
1869 }
1870
1871 // PMCG Nodes
1872 if (PmcgNodeCount > 0) {
1873 PmcgOffset = (UINT32)TableSize;
1874 // Size of PMCG node list.
1875 NodeSize = GetSizeofPmcgNodes (
1876 PmcgOffset,
1877 PmcgNodeList,
1878 PmcgNodeCount,
1879 &NodeIndexer
1880 );
1881 if (NodeSize > MAX_UINT32) {
1882 Status = EFI_INVALID_PARAMETER;
1883 DEBUG ((
1884 DEBUG_ERROR,
1885 "ERROR: IORT: Invalid Size of PMCG Nodes. Status = %r\n",
1886 Status
1887 ));
1888 goto error_handler;
1889 }
1890 TableSize += NodeSize;
1891
1892 DEBUG ((
1893 DEBUG_INFO,
1894 " PmcgNodeCount = %d\n" \
1895 " PmcgOffset = %d\n",
1896 PmcgNodeCount,
1897 PmcgOffset
1898 ));
1899 }
1900
1901 DEBUG ((
1902 DEBUG_INFO,
1903 "INFO: IORT:\n" \
1904 " IortNodeCount = %d\n" \
1905 " TableSize = 0x%lx\n",
1906 IortNodeCount,
1907 TableSize
1908 ));
1909
1910 if (TableSize > MAX_UINT32) {
1911 Status = EFI_INVALID_PARAMETER;
1912 DEBUG ((
1913 DEBUG_ERROR,
1914 "ERROR: IORT: IORT Table Size 0x%lx > MAX_UINT32," \
1915 " Status = %r\n",
1916 TableSize,
1917 Status
1918 ));
1919 goto error_handler;
1920 }
1921
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;
1926 DEBUG ((
1927 DEBUG_ERROR,
1928 "ERROR: IORT: Failed to allocate memory for IORT Table, Size = %d," \
1929 " Status = %r\n",
1930 TableSize,
1931 Status
1932 ));
1933 goto error_handler;
1934 }
1935
1936 Iort = (EFI_ACPI_6_0_IO_REMAPPING_TABLE*)*Table;
1937
1938 DEBUG ((
1939 DEBUG_INFO,
1940 "IORT: Iort = 0x%p TableSize = 0x%lx\n",
1941 Iort,
1942 TableSize
1943 ));
1944
1945 Status = AddAcpiHeader (
1946 CfgMgrProtocol,
1947 This,
1948 &Iort->Header,
1949 AcpiTableInfo,
1950 (UINT32)TableSize
1951 );
1952 if (EFI_ERROR (Status)) {
1953 DEBUG ((
1954 DEBUG_ERROR,
1955 "ERROR: IORT: Failed to add ACPI header. Status = %r\n",
1956 Status
1957 ));
1958 goto error_handler;
1959 }
1960
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;
1965
1966 if (ItsGroupNodeCount > 0) {
1967 Status = AddItsGroupNodes (
1968 This,
1969 CfgMgrProtocol,
1970 Iort,
1971 ItsGroupOffset,
1972 ItsGroupNodeList,
1973 ItsGroupNodeCount
1974 );
1975 if (EFI_ERROR (Status)) {
1976 DEBUG ((
1977 DEBUG_ERROR,
1978 "ERROR: IORT: Failed to add ITS Group Node. Status = %r\n",
1979 Status
1980 ));
1981 goto error_handler;
1982 }
1983 }
1984
1985 if (NamedComponentNodeCount > 0) {
1986 Status = AddNamedComponentNodes (
1987 This,
1988 CfgMgrProtocol,
1989 Iort,
1990 NamedComponentOffset,
1991 NamedComponentNodeList,
1992 NamedComponentNodeCount
1993 );
1994 if (EFI_ERROR (Status)) {
1995 DEBUG ((
1996 DEBUG_ERROR,
1997 "ERROR: IORT: Failed to add Named Component Node. Status = %r\n",
1998 Status
1999 ));
2000 goto error_handler;
2001 }
2002 }
2003
2004 if (RootComplexNodeCount > 0) {
2005 Status = AddRootComplexNodes (
2006 This,
2007 CfgMgrProtocol,
2008 Iort,
2009 RootComplexOffset,
2010 RootComplexNodeList,
2011 RootComplexNodeCount
2012 );
2013 if (EFI_ERROR (Status)) {
2014 DEBUG ((
2015 DEBUG_ERROR,
2016 "ERROR: IORT: Failed to add Root Complex Node. Status = %r\n",
2017 Status
2018 ));
2019 goto error_handler;
2020 }
2021 }
2022
2023 if (SmmuV1V2NodeCount > 0) {
2024 Status = AddSmmuV1V2Nodes (
2025 This,
2026 CfgMgrProtocol,
2027 Iort,
2028 SmmuV1V2Offset,
2029 SmmuV1V2NodeList,
2030 SmmuV1V2NodeCount
2031 );
2032 if (EFI_ERROR (Status)) {
2033 DEBUG ((
2034 DEBUG_ERROR,
2035 "ERROR: IORT: Failed to add SMMU v1/v2 Node. Status = %r\n",
2036 Status
2037 ));
2038 goto error_handler;
2039 }
2040 }
2041
2042 if (SmmuV3NodeCount > 0) {
2043 Status = AddSmmuV3Nodes (
2044 This,
2045 CfgMgrProtocol,
2046 Iort,
2047 SmmuV3Offset,
2048 SmmuV3NodeList,
2049 SmmuV3NodeCount
2050 );
2051 if (EFI_ERROR (Status)) {
2052 DEBUG ((
2053 DEBUG_ERROR,
2054 "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
2055 Status
2056 ));
2057 goto error_handler;
2058 }
2059 }
2060
2061 if (PmcgNodeCount > 0) {
2062 Status = AddPmcgNodes (
2063 This,
2064 CfgMgrProtocol,
2065 Iort,
2066 PmcgOffset,
2067 PmcgNodeList,
2068 PmcgNodeCount
2069 );
2070 if (EFI_ERROR (Status)) {
2071 DEBUG ((
2072 DEBUG_ERROR,
2073 "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
2074 Status
2075 ));
2076 goto error_handler;
2077 }
2078 }
2079
2080 return EFI_SUCCESS;
2081
2082 error_handler:
2083 if (Generator->NodeIndexer != NULL) {
2084 FreePool (Generator->NodeIndexer);
2085 Generator->NodeIndexer = NULL;
2086 }
2087
2088 if (*Table != NULL) {
2089 FreePool (*Table);
2090 *Table = NULL;
2091 }
2092 return Status;
2093 }
2094
2095 /** Free any resources allocated for constructing the IORT
2096
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
2100 Protocol Interface.
2101 @param [in, out] Table Pointer to the ACPI Table.
2102
2103 @retval EFI_SUCCESS The resources were freed successfully.
2104 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
2105 **/
2106 STATIC
2107 EFI_STATUS
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
2113 )
2114 {
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);
2121
2122 Generator = (ACPI_IORT_GENERATOR*)This;
2123
2124 // Free any memory allocated by the generator
2125 if (Generator->NodeIndexer != NULL) {
2126 FreePool (Generator->NodeIndexer);
2127 Generator->NodeIndexer = NULL;
2128 }
2129
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;
2134 }
2135
2136 FreePool (*Table);
2137 *Table = NULL;
2138 return EFI_SUCCESS;
2139 }
2140
2141 /** The IORT Table Generator revision.
2142 */
2143 #define IORT_GENERATOR_REVISION CREATE_REVISION (1, 0)
2144
2145 /** The interface for the MADT Table Generator.
2146 */
2147 STATIC
2148 ACPI_IORT_GENERATOR IortGenerator = {
2149 // ACPI table generator header
2150 {
2151 // Generator ID
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,
2161 // Creator ID
2162 TABLE_GENERATOR_CREATOR_ID_ARM,
2163 // Creator Revision
2164 IORT_GENERATOR_REVISION,
2165 // Build Table function
2166 BuildIortTable,
2167 // Free Resource function
2168 FreeIortTableResources,
2169 // Extended build function not needed
2170 NULL,
2171 // Extended build function not implemented by the generator.
2172 // Hence extended free resource function is not required.
2173 NULL
2174 },
2175
2176 // IORT Generator private data
2177
2178 // Iort Node count
2179 0,
2180 // Pointer to Iort node indexer
2181 NULL
2182 };
2183
2184 /** Register the Generator with the ACPI Table Factory.
2185
2186 @param [in] ImageHandle The handle to the image.
2187 @param [in] SystemTable Pointer to the System Table.
2188
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.
2193 **/
2194 EFI_STATUS
2195 EFIAPI
2196 AcpiIortLibConstructor (
2197 IN EFI_HANDLE ImageHandle,
2198 IN EFI_SYSTEM_TABLE * SystemTable
2199 )
2200 {
2201 EFI_STATUS Status;
2202 Status = RegisterAcpiTableGenerator (&IortGenerator.Header);
2203 DEBUG ((DEBUG_INFO, "IORT: Register Generator. Status = %r\n", Status));
2204 ASSERT_EFI_ERROR (Status);
2205 return Status;
2206 }
2207
2208 /** Deregister the Generator from the ACPI Table Factory.
2209
2210 @param [in] ImageHandle The handle to the image.
2211 @param [in] SystemTable Pointer to the System Table.
2212
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.
2216 **/
2217 EFI_STATUS
2218 EFIAPI
2219 AcpiIortLibDestructor (
2220 IN EFI_HANDLE ImageHandle,
2221 IN EFI_SYSTEM_TABLE * SystemTable
2222 )
2223 {
2224 EFI_STATUS Status;
2225 Status = DeregisterAcpiTableGenerator (&IortGenerator.Header);
2226 DEBUG ((DEBUG_INFO, "Iort: Deregister Generator. Status = %r\n", Status));
2227 ASSERT_EFI_ERROR (Status);
2228 return Status;
2229 }