]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiIortLibArm / IortGenerator.c
1 /** @file
2 IORT Table Generator
3
4 Copyright (c) 2017 - 2022, 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, Revision E.d, Feb 2022
9 (https://developer.arm.com/documentation/den0049/)
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 - EArmObjRmr
41 - EArmObjGicItsIdentifierArray
42 - EArmObjIdMappingArray
43 - EArmObjSmmuInterruptArray
44 - EArmObjMemoryRangeDescriptor
45 */
46
47 /** This macro expands to a function that retrieves the ITS
48 Group node information from the Configuration Manager.
49 */
50 GET_OBJECT_LIST (
51 EObjNameSpaceArm,
52 EArmObjItsGroup,
53 CM_ARM_ITS_GROUP_NODE
54 );
55
56 /** This macro expands to a function that retrieves the
57 Named Component node information from the Configuration Manager.
58 */
59 GET_OBJECT_LIST (
60 EObjNameSpaceArm,
61 EArmObjNamedComponent,
62 CM_ARM_NAMED_COMPONENT_NODE
63 );
64
65 /** This macro expands to a function that retrieves the
66 Root Complex node information from the Configuration Manager.
67 */
68 GET_OBJECT_LIST (
69 EObjNameSpaceArm,
70 EArmObjRootComplex,
71 CM_ARM_ROOT_COMPLEX_NODE
72 );
73
74 /** This macro expands to a function that retrieves the
75 SMMU v1/v2 node information from the Configuration Manager.
76 */
77 GET_OBJECT_LIST (
78 EObjNameSpaceArm,
79 EArmObjSmmuV1SmmuV2,
80 CM_ARM_SMMUV1_SMMUV2_NODE
81 );
82
83 /** This macro expands to a function that retrieves the
84 SMMU v3 node information from the Configuration Manager.
85 */
86 GET_OBJECT_LIST (
87 EObjNameSpaceArm,
88 EArmObjSmmuV3,
89 CM_ARM_SMMUV3_NODE
90 );
91
92 /** This macro expands to a function that retrieves the
93 PMCG node information from the Configuration Manager.
94 */
95 GET_OBJECT_LIST (
96 EObjNameSpaceArm,
97 EArmObjPmcg,
98 CM_ARM_PMCG_NODE
99 );
100
101 /** This macro expands to a function that retrieves the
102 RMR node information from the Configuration Manager.
103 */
104 GET_OBJECT_LIST (
105 EObjNameSpaceArm,
106 EArmObjRmr,
107 CM_ARM_RMR_NODE
108 );
109
110 /** This macro expands to a function that retrieves the
111 Memory Range Descriptor Array information from the Configuration Manager.
112 */
113 GET_OBJECT_LIST (
114 EObjNameSpaceArm,
115 EArmObjMemoryRangeDescriptor,
116 CM_ARM_MEMORY_RANGE_DESCRIPTOR
117 );
118
119 /** This macro expands to a function that retrieves the
120 ITS Identifier Array information from the Configuration Manager.
121 */
122 GET_OBJECT_LIST (
123 EObjNameSpaceArm,
124 EArmObjGicItsIdentifierArray,
125 CM_ARM_ITS_IDENTIFIER
126 );
127
128 /** This macro expands to a function that retrieves the
129 Id Mapping Array information from the Configuration Manager.
130 */
131 GET_OBJECT_LIST (
132 EObjNameSpaceArm,
133 EArmObjIdMappingArray,
134 CM_ARM_ID_MAPPING
135 );
136
137 /** This macro expands to a function that retrieves the
138 SMMU Interrupt Array information from the Configuration Manager.
139 */
140 GET_OBJECT_LIST (
141 EObjNameSpaceArm,
142 EArmObjSmmuInterruptArray,
143 CM_ARM_SMMU_INTERRUPT
144 );
145
146 /** Returns the size of the ITS Group node.
147
148 @param [in] Node Pointer to ITS Group node.
149
150 @retval Size of the ITS Group Node.
151 **/
152 STATIC
153 UINT32
154 GetItsGroupNodeSize (
155 IN CONST CM_ARM_ITS_GROUP_NODE *Node
156 )
157 {
158 ASSERT (Node != NULL);
159
160 /* Size of ITS Group Node +
161 Size of ITS Identifier array
162 */
163 return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE) +
164 (Node->ItsIdCount * sizeof (UINT32)));
165 }
166
167 /** Returns the total size required for the ITS Group nodes and
168 updates the Node Indexer.
169
170 This function calculates the size required for the node group
171 and also populates the Node Indexer array with offsets for the
172 individual nodes.
173
174 @param [in] NodeStartOffset Offset from the start of the
175 IORT where this node group starts.
176 @param [in] NodeList Pointer to ITS Group node list.
177 @param [in] NodeCount Count of the ITS Group nodes.
178 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
179
180 @retval Total size of the ITS Group Nodes.
181 **/
182 STATIC
183 UINT64
184 GetSizeofItsGroupNodes (
185 IN CONST UINT32 NodeStartOffset,
186 IN CONST CM_ARM_ITS_GROUP_NODE *NodeList,
187 IN UINT32 NodeCount,
188 IN OUT IORT_NODE_INDEXER **CONST NodeIndexer
189 )
190 {
191 UINT64 Size;
192
193 ASSERT (NodeList != NULL);
194
195 Size = 0;
196 while (NodeCount-- != 0) {
197 (*NodeIndexer)->Token = NodeList->Token;
198 (*NodeIndexer)->Object = (VOID *)NodeList;
199 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
200 (*NodeIndexer)->Identifier = NodeList->Identifier;
201 DEBUG ((
202 DEBUG_INFO,
203 "IORT: Node Indexer = %p, Token = %p, Object = %p,"
204 " Offset = 0x%x, Identifier = 0x%x\n",
205 *NodeIndexer,
206 (*NodeIndexer)->Token,
207 (*NodeIndexer)->Object,
208 (*NodeIndexer)->Offset,
209 (*NodeIndexer)->Identifier
210 ));
211
212 Size += GetItsGroupNodeSize (NodeList);
213 (*NodeIndexer)++;
214 NodeList++;
215 }
216
217 return Size;
218 }
219
220 /** Returns the size of the Named Component node.
221
222 @param [in] Node Pointer to Named Component node.
223
224 @retval Size of the Named Component node.
225 **/
226 STATIC
227 UINT32
228 GetNamedComponentNodeSize (
229 IN CONST CM_ARM_NAMED_COMPONENT_NODE *Node
230 )
231 {
232 ASSERT (Node != NULL);
233
234 /* Size of Named Component node +
235 Size of ID mapping array +
236 Size of ASCII string + 'padding to 32-bit word aligned'.
237 */
238 return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE) +
239 (Node->IdMappingCount *
240 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) +
241 ALIGN_VALUE (AsciiStrSize (Node->ObjectName), 4));
242 }
243
244 /** Returns the total size required for the Named Component nodes and
245 updates the Node Indexer.
246
247 This function calculates the size required for the node group
248 and also populates the Node Indexer array with offsets for the
249 individual nodes.
250
251 @param [in] NodeStartOffset Offset from the start of the
252 IORT where this node group starts.
253 @param [in] NodeList Pointer to Named Component node list.
254 @param [in] NodeCount Count of the Named Component nodes.
255 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
256
257 @retval Total size of the Named Component nodes.
258 **/
259 STATIC
260 UINT64
261 GetSizeofNamedComponentNodes (
262 IN CONST UINT32 NodeStartOffset,
263 IN CONST CM_ARM_NAMED_COMPONENT_NODE *NodeList,
264 IN UINT32 NodeCount,
265 IN OUT IORT_NODE_INDEXER **CONST NodeIndexer
266 )
267 {
268 UINT64 Size;
269
270 ASSERT (NodeList != NULL);
271
272 Size = 0;
273 while (NodeCount-- != 0) {
274 (*NodeIndexer)->Token = NodeList->Token;
275 (*NodeIndexer)->Object = (VOID *)NodeList;
276 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
277 (*NodeIndexer)->Identifier = NodeList->Identifier;
278 DEBUG ((
279 DEBUG_INFO,
280 "IORT: Node Indexer = %p, Token = %p, Object = %p,"
281 " Offset = 0x%x, Identifier = 0x%x\n",
282 *NodeIndexer,
283 (*NodeIndexer)->Token,
284 (*NodeIndexer)->Object,
285 (*NodeIndexer)->Offset,
286 (*NodeIndexer)->Identifier
287 ));
288
289 Size += GetNamedComponentNodeSize (NodeList);
290 (*NodeIndexer)++;
291 NodeList++;
292 }
293
294 return Size;
295 }
296
297 /** Returns the size of the Root Complex node.
298
299 @param [in] Node Pointer to Root Complex node.
300
301 @retval Size of the Root Complex node.
302 **/
303 STATIC
304 UINT32
305 GetRootComplexNodeSize (
306 IN CONST CM_ARM_ROOT_COMPLEX_NODE *Node
307 )
308 {
309 ASSERT (Node != NULL);
310
311 /* Size of Root Complex node +
312 Size of ID mapping array
313 */
314 return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE) +
315 (Node->IdMappingCount *
316 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)));
317 }
318
319 /** Returns the total size required for the Root Complex nodes and
320 updates the Node Indexer.
321
322 This function calculates the size required for the node group
323 and also populates the Node Indexer array with offsets for the
324 individual nodes.
325
326 @param [in] NodeStartOffset Offset from the start of the
327 IORT where this node group starts.
328 @param [in] NodeList Pointer to Root Complex node list.
329 @param [in] NodeCount Count of the Root Complex nodes.
330 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
331
332 @retval Total size of the Root Complex nodes.
333 **/
334 STATIC
335 UINT64
336 GetSizeofRootComplexNodes (
337 IN CONST UINT32 NodeStartOffset,
338 IN CONST CM_ARM_ROOT_COMPLEX_NODE *NodeList,
339 IN UINT32 NodeCount,
340 IN OUT IORT_NODE_INDEXER **CONST NodeIndexer
341 )
342 {
343 UINT64 Size;
344
345 ASSERT (NodeList != NULL);
346
347 Size = 0;
348 while (NodeCount-- != 0) {
349 (*NodeIndexer)->Token = NodeList->Token;
350 (*NodeIndexer)->Object = (VOID *)NodeList;
351 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
352 (*NodeIndexer)->Identifier = NodeList->Identifier;
353 DEBUG ((
354 DEBUG_INFO,
355 "IORT: Node Indexer = %p, Token = %p, Object = %p,"
356 " Offset = 0x%x, Identifier = 0x%x\n",
357 *NodeIndexer,
358 (*NodeIndexer)->Token,
359 (*NodeIndexer)->Object,
360 (*NodeIndexer)->Offset,
361 (*NodeIndexer)->Identifier
362 ));
363
364 Size += GetRootComplexNodeSize (NodeList);
365 (*NodeIndexer)++;
366 NodeList++;
367 }
368
369 return Size;
370 }
371
372 /** Returns the size of the SMMUv1/SMMUv2 node.
373
374 @param [in] Node Pointer to SMMUv1/SMMUv2 node list.
375
376 @retval Size of the SMMUv1/SMMUv2 node.
377 **/
378 STATIC
379 UINT32
380 GetSmmuV1V2NodeSize (
381 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE *Node
382 )
383 {
384 ASSERT (Node != NULL);
385
386 /* Size of SMMU v1/SMMU v2 node +
387 Size of ID mapping array +
388 Size of context interrupt array +
389 Size of PMU interrupt array
390 */
391 return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE) +
392 (Node->IdMappingCount *
393 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) +
394 (Node->ContextInterruptCount *
395 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)) +
396 (Node->PmuInterruptCount *
397 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)));
398 }
399
400 /** Returns the total size required for the SMMUv1/SMMUv2 nodes and
401 updates the Node Indexer.
402
403 This function calculates the size required for the node group
404 and also populates the Node Indexer array with offsets for the
405 individual nodes.
406
407 @param [in] NodeStartOffset Offset from the start of the
408 IORT where this node group starts.
409 @param [in] NodeList Pointer to SMMUv1/SMMUv2 node list.
410 @param [in] NodeCount Count of the SMMUv1/SMMUv2 nodes.
411 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
412
413 @retval Total size of the SMMUv1/SMMUv2 nodes.
414 **/
415 STATIC
416 UINT64
417 GetSizeofSmmuV1V2Nodes (
418 IN CONST UINT32 NodeStartOffset,
419 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE *NodeList,
420 IN UINT32 NodeCount,
421 IN OUT IORT_NODE_INDEXER **CONST NodeIndexer
422 )
423 {
424 UINT64 Size;
425
426 ASSERT (NodeList != NULL);
427
428 Size = 0;
429 while (NodeCount-- != 0) {
430 (*NodeIndexer)->Token = NodeList->Token;
431 (*NodeIndexer)->Object = (VOID *)NodeList;
432 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
433 (*NodeIndexer)->Identifier = NodeList->Identifier;
434 DEBUG ((
435 DEBUG_INFO,
436 "IORT: Node Indexer = %p, Token = %p, Object = %p,"
437 " Offset = 0x%x, Identifier = 0x%x\n",
438 *NodeIndexer,
439 (*NodeIndexer)->Token,
440 (*NodeIndexer)->Object,
441 (*NodeIndexer)->Offset,
442 (*NodeIndexer)->Identifier
443 ));
444
445 Size += GetSmmuV1V2NodeSize (NodeList);
446 (*NodeIndexer)++;
447 NodeList++;
448 }
449
450 return Size;
451 }
452
453 /** Returns the size of the SMMUv3 node.
454
455 @param [in] Node Pointer to SMMUv3 node list.
456
457 @retval Total size of the SMMUv3 nodes.
458 **/
459 STATIC
460 UINT32
461 GetSmmuV3NodeSize (
462 IN CONST CM_ARM_SMMUV3_NODE *Node
463 )
464 {
465 ASSERT (Node != NULL);
466
467 /* Size of SMMU v1/SMMU v2 node +
468 Size of ID mapping array
469 */
470 return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE) +
471 (Node->IdMappingCount *
472 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)));
473 }
474
475 /** Returns the total size required for the SMMUv3 nodes and
476 updates the Node Indexer.
477
478 This function calculates the size required for the node group
479 and also populates the Node Indexer array with offsets for the
480 individual nodes.
481
482 @param [in] NodeStartOffset Offset from the start of the
483 IORT where this node group starts.
484 @param [in] NodeList Pointer to SMMUv3 node list.
485 @param [in] NodeCount Count of the SMMUv3 nodes.
486 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
487
488 @retval Total size of the SMMUv3 nodes.
489 **/
490 STATIC
491 UINT64
492 GetSizeofSmmuV3Nodes (
493 IN CONST UINT32 NodeStartOffset,
494 IN CONST CM_ARM_SMMUV3_NODE *NodeList,
495 IN UINT32 NodeCount,
496 IN OUT IORT_NODE_INDEXER **CONST NodeIndexer
497 )
498 {
499 UINT64 Size;
500
501 ASSERT (NodeList != NULL);
502
503 Size = 0;
504 while (NodeCount-- != 0) {
505 (*NodeIndexer)->Token = NodeList->Token;
506 (*NodeIndexer)->Object = (VOID *)NodeList;
507 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
508 (*NodeIndexer)->Identifier = NodeList->Identifier;
509 DEBUG ((
510 DEBUG_INFO,
511 "IORT: Node Indexer = %p, Token = %p, Object = %p,"
512 " Offset = 0x%x, Identifier = 0x%x\n",
513 *NodeIndexer,
514 (*NodeIndexer)->Token,
515 (*NodeIndexer)->Object,
516 (*NodeIndexer)->Offset,
517 (*NodeIndexer)->Identifier
518 ));
519
520 Size += GetSmmuV3NodeSize (NodeList);
521 (*NodeIndexer)++;
522 NodeList++;
523 }
524
525 return Size;
526 }
527
528 /** Returns the size of the PMCG node.
529
530 @param [in] Node Pointer to PMCG node.
531
532 @retval Size of the PMCG node.
533 **/
534 STATIC
535 UINT32
536 GetPmcgNodeSize (
537 IN CONST CM_ARM_PMCG_NODE *Node
538 )
539 {
540 ASSERT (Node != NULL);
541
542 /* Size of PMCG node +
543 Size of ID mapping array
544 */
545 return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE) +
546 (Node->IdMappingCount *
547 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)));
548 }
549
550 /** Returns the total size required for the PMCG nodes and
551 updates the Node Indexer.
552
553 This function calculates the size required for the node group
554 and also populates the Node Indexer array with offsets for the
555 individual nodes.
556
557 @param [in] NodeStartOffset Offset from the start of the
558 IORT where this node group starts.
559 @param [in] NodeList Pointer to PMCG node list.
560 @param [in] NodeCount Count of the PMCG nodes.
561 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
562
563 @retval Total size of the PMCG nodes.
564 **/
565 STATIC
566 UINT64
567 GetSizeofPmcgNodes (
568 IN CONST UINT32 NodeStartOffset,
569 IN CONST CM_ARM_PMCG_NODE *NodeList,
570 IN UINT32 NodeCount,
571 IN OUT IORT_NODE_INDEXER **CONST NodeIndexer
572 )
573 {
574 UINT64 Size;
575
576 ASSERT (NodeList != NULL);
577
578 Size = 0;
579 while (NodeCount-- != 0) {
580 (*NodeIndexer)->Token = NodeList->Token;
581 (*NodeIndexer)->Object = (VOID *)NodeList;
582 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
583 (*NodeIndexer)->Identifier = NodeList->Identifier;
584 DEBUG ((
585 DEBUG_INFO,
586 "IORT: Node Indexer = %p, Token = %p, Object = %p,"
587 " Offset = 0x%x, Identifier = 0x%x\n",
588 *NodeIndexer,
589 (*NodeIndexer)->Token,
590 (*NodeIndexer)->Object,
591 (*NodeIndexer)->Offset,
592 (*NodeIndexer)->Identifier
593 ));
594
595 Size += GetPmcgNodeSize (NodeList);
596 (*NodeIndexer)++;
597 NodeList++;
598 }
599
600 return Size;
601 }
602
603 /** Returns the size of the RMR node.
604
605 @param [in] Node Pointer to RMR node.
606
607 @retval Size of the RMR node.
608 **/
609 STATIC
610 UINT32
611 GetRmrNodeSize (
612 IN CONST CM_ARM_RMR_NODE *Node
613 )
614 {
615 ASSERT (Node != NULL);
616
617 /* Size of RMR node +
618 Size of ID mapping array +
619 Size of Memory Range Descriptor array
620 */
621 return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE) +
622 (Node->IdMappingCount *
623 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) +
624 (Node->MemRangeDescCount *
625 sizeof (EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC)));
626 }
627
628 /** Returns the total size required for the RMR nodes and
629 updates the Node Indexer.
630
631 This function calculates the size required for the node group
632 and also populates the Node Indexer array with offsets for the
633 individual nodes.
634
635 @param [in] NodeStartOffset Offset from the start of the
636 IORT where this node group starts.
637 @param [in] NodeList Pointer to RMR node list.
638 @param [in] NodeCount Count of the RMR nodes.
639 @param [in, out] NodeIndexer Pointer to the next Node Indexer.
640
641 @retval Total size of the RMR nodes.
642 **/
643 STATIC
644 UINT64
645 GetSizeofRmrNodes (
646 IN CONST UINT32 NodeStartOffset,
647 IN CONST CM_ARM_RMR_NODE *NodeList,
648 IN UINT32 NodeCount,
649 IN OUT IORT_NODE_INDEXER **CONST NodeIndexer
650 )
651 {
652 UINT64 Size;
653
654 ASSERT (NodeList != NULL);
655
656 Size = 0;
657 while (NodeCount-- != 0) {
658 (*NodeIndexer)->Token = NodeList->Token;
659 (*NodeIndexer)->Object = (VOID *)NodeList;
660 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
661 (*NodeIndexer)->Identifier = NodeList->Identifier;
662 DEBUG ((
663 DEBUG_INFO,
664 "IORT: Node Indexer = %p, Token = %p, Object = %p,"
665 " Offset = 0x%x, Identifier = 0x%x\n",
666 *NodeIndexer,
667 (*NodeIndexer)->Token,
668 (*NodeIndexer)->Object,
669 (*NodeIndexer)->Offset,
670 (*NodeIndexer)->Identifier
671 ));
672
673 Size += GetRmrNodeSize (NodeList);
674 (*NodeIndexer)++;
675 NodeList++;
676 }
677
678 return Size;
679 }
680
681 /** Returns the offset of the Node referenced by the Token.
682
683 @param [in] NodeIndexer Pointer to node indexer array.
684 @param [in] NodeCount Count of the nodes.
685 @param [in] Token Reference token for the node.
686 @param [out] NodeOffset Offset of the node from the
687 start of the IORT table.
688
689 @retval EFI_SUCCESS Success.
690 @retval EFI_NOT_FOUND No matching token reference
691 found in node indexer array.
692 **/
693 STATIC
694 EFI_STATUS
695 GetNodeOffsetReferencedByToken (
696 IN IORT_NODE_INDEXER *NodeIndexer,
697 IN UINT32 NodeCount,
698 IN CM_OBJECT_TOKEN Token,
699 OUT UINT32 *NodeOffset
700 )
701 {
702 DEBUG ((
703 DEBUG_INFO,
704 "IORT: Node Indexer: Search Token = %p\n",
705 Token
706 ));
707 while (NodeCount-- != 0) {
708 DEBUG ((
709 DEBUG_INFO,
710 "IORT: Node Indexer: NodeIndexer->Token = %p, Offset = %d\n",
711 NodeIndexer->Token,
712 NodeIndexer->Offset
713 ));
714 if (NodeIndexer->Token == Token) {
715 *NodeOffset = NodeIndexer->Offset;
716 DEBUG ((
717 DEBUG_INFO,
718 "IORT: Node Indexer: Token = %p, Found\n",
719 Token
720 ));
721 return EFI_SUCCESS;
722 }
723
724 NodeIndexer++;
725 }
726
727 DEBUG ((
728 DEBUG_INFO,
729 "IORT: Node Indexer: Token = %p, Not Found\n",
730 Token
731 ));
732 return EFI_NOT_FOUND;
733 }
734
735 /** Update the Id Mapping Array.
736
737 This function retrieves the Id Mapping Array object referenced by the
738 IdMappingToken and updates the IdMapArray.
739
740 @param [in] This Pointer to the table Generator.
741 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
742 Protocol Interface.
743 @param [in] IdMapArray Pointer to an array of Id Mappings.
744 @param [in] IdCount Number of Id Mappings.
745 @param [in] IdMappingToken Reference Token for retrieving the
746 Id Mapping Array object.
747
748 @retval EFI_SUCCESS Table generated successfully.
749 @retval EFI_INVALID_PARAMETER A parameter is invalid.
750 @retval EFI_NOT_FOUND The required object was not found.
751 **/
752 STATIC
753 EFI_STATUS
754 AddIdMappingArray (
755 IN CONST ACPI_TABLE_GENERATOR *CONST This,
756 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
757 IN EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray,
758 IN UINT32 IdCount,
759 IN CONST CM_OBJECT_TOKEN IdMappingToken
760 )
761 {
762 EFI_STATUS Status;
763 CM_ARM_ID_MAPPING *IdMappings;
764 UINT32 IdMappingCount;
765 ACPI_IORT_GENERATOR *Generator;
766
767 ASSERT (IdMapArray != NULL);
768
769 Generator = (ACPI_IORT_GENERATOR *)This;
770
771 // Get the Id Mapping Array
772 Status = GetEArmObjIdMappingArray (
773 CfgMgrProtocol,
774 IdMappingToken,
775 &IdMappings,
776 &IdMappingCount
777 );
778 if (EFI_ERROR (Status)) {
779 DEBUG ((
780 DEBUG_ERROR,
781 "ERROR: IORT: Failed to get Id Mapping array. Status = %r\n",
782 Status
783 ));
784 return Status;
785 }
786
787 if (IdMappingCount < IdCount) {
788 DEBUG ((
789 DEBUG_ERROR,
790 "ERROR: IORT: Failed to get the required number of Id Mappings.\n"
791 ));
792 return EFI_NOT_FOUND;
793 }
794
795 // Populate the Id Mapping array
796 while (IdCount-- != 0) {
797 Status = GetNodeOffsetReferencedByToken (
798 Generator->NodeIndexer,
799 Generator->IortNodeCount,
800 IdMappings->OutputReferenceToken,
801 &IdMapArray->OutputReference
802 );
803 if (EFI_ERROR (Status)) {
804 DEBUG ((
805 DEBUG_ERROR,
806 "ERROR: IORT: Failed to get Output Reference for ITS Identifier array."
807 "Reference Token = %p"
808 " Status = %r\n",
809 IdMappings->OutputReferenceToken,
810 Status
811 ));
812 return Status;
813 }
814
815 IdMapArray->InputBase = IdMappings->InputBase;
816 IdMapArray->NumIds = IdMappings->NumIds;
817 IdMapArray->OutputBase = IdMappings->OutputBase;
818 IdMapArray->Flags = IdMappings->Flags;
819
820 IdMapArray++;
821 IdMappings++;
822 } // Id Mapping array
823
824 return EFI_SUCCESS;
825 }
826
827 /** Update the ITS Group Node Information.
828
829 @param [in] This Pointer to the table Generator.
830 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
831 Protocol Interface.
832 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
833 @param [in] Iort Pointer to IORT table structure.
834 @param [in] NodesStartOffset Offset for the start of the ITS Group
835 Nodes.
836 @param [in] NodeList Pointer to an array of ITS Group Node
837 Objects.
838 @param [in] NodeCount Number of ITS Group Node Objects.
839
840 @retval EFI_SUCCESS Table generated successfully.
841 @retval EFI_INVALID_PARAMETER A parameter is invalid.
842 @retval EFI_NOT_FOUND The required object was not found.
843 **/
844 STATIC
845 EFI_STATUS
846 AddItsGroupNodes (
847 IN CONST ACPI_TABLE_GENERATOR *CONST This,
848 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
849 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
850 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,
851 IN CONST UINT32 NodesStartOffset,
852 IN CONST CM_ARM_ITS_GROUP_NODE *NodeList,
853 IN UINT32 NodeCount
854 )
855 {
856 EFI_STATUS Status;
857 EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE *ItsGroupNode;
858 UINT32 *ItsIds;
859 CM_ARM_ITS_IDENTIFIER *ItsIdentifier;
860 UINT32 ItsIdentifierCount;
861 UINT32 IdIndex;
862 UINT64 NodeLength;
863
864 ASSERT (Iort != NULL);
865
866 ItsGroupNode = (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE *)((UINT8 *)Iort +
867 NodesStartOffset);
868
869 while (NodeCount-- != 0) {
870 NodeLength = GetItsGroupNodeSize (NodeList);
871 if (NodeLength > MAX_UINT16) {
872 Status = EFI_INVALID_PARAMETER;
873 DEBUG ((
874 DEBUG_ERROR,
875 "ERROR: IORT: ITS Id Array Node length 0x%lx > MAX_UINT16."
876 " Status = %r\n",
877 NodeLength,
878 Status
879 ));
880 return Status;
881 }
882
883 // Populate the node header
884 ItsGroupNode->Node.Type = EFI_ACPI_IORT_TYPE_ITS_GROUP;
885 ItsGroupNode->Node.Length = (UINT16)NodeLength;
886 ItsGroupNode->Node.NumIdMappings = 0;
887 ItsGroupNode->Node.IdReference = 0;
888
889 if (AcpiTableInfo->AcpiTableRevision <
890 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
891 {
892 ItsGroupNode->Node.Revision = 0;
893 ItsGroupNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
894 } else {
895 ItsGroupNode->Node.Revision = 1;
896 ItsGroupNode->Node.Identifier = NodeList->Identifier;
897 }
898
899 // IORT specific data
900 ItsGroupNode->NumItsIdentifiers = NodeList->ItsIdCount;
901 ItsIds = (UINT32 *)((UINT8 *)ItsGroupNode +
902 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE));
903
904 Status = GetEArmObjGicItsIdentifierArray (
905 CfgMgrProtocol,
906 NodeList->ItsIdToken,
907 &ItsIdentifier,
908 &ItsIdentifierCount
909 );
910 if (EFI_ERROR (Status)) {
911 DEBUG ((
912 DEBUG_ERROR,
913 "ERROR: IORT: Failed to get ITS Identifier array. Status = %r\n",
914 Status
915 ));
916 return Status;
917 }
918
919 if (ItsIdentifierCount < ItsGroupNode->NumItsIdentifiers) {
920 DEBUG ((
921 DEBUG_ERROR,
922 "ERROR: IORT: Failed to get the required number of ITS Identifiers.\n"
923 ));
924 return EFI_NOT_FOUND;
925 }
926
927 // Populate the ITS identifier array
928 for (IdIndex = 0; IdIndex < ItsGroupNode->NumItsIdentifiers; IdIndex++) {
929 ItsIds[IdIndex] = ItsIdentifier[IdIndex].ItsId;
930 } // ITS identifier array
931
932 // Next IORT Group Node
933 ItsGroupNode = (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE *)((UINT8 *)ItsGroupNode +
934 ItsGroupNode->Node.Length);
935 NodeList++;
936 } // IORT Group Node
937
938 return EFI_SUCCESS;
939 }
940
941 /** Update the Named Component Node Information.
942
943 This function updates the Named Component node information in the IORT
944 table.
945
946 @param [in] This Pointer to the table Generator.
947 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
948 Protocol Interface.
949 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
950 @param [in] Iort Pointer to IORT table structure.
951 @param [in] NodesStartOffset Offset for the start of the Named
952 Component Nodes.
953 @param [in] NodeList Pointer to an array of Named Component
954 Node Objects.
955 @param [in] NodeCount Number of Named Component Node Objects.
956
957 @retval EFI_SUCCESS Table generated successfully.
958 @retval EFI_INVALID_PARAMETER A parameter is invalid.
959 @retval EFI_NOT_FOUND The required object was not found.
960 **/
961 STATIC
962 EFI_STATUS
963 AddNamedComponentNodes (
964 IN CONST ACPI_TABLE_GENERATOR *CONST This,
965 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
966 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
967 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,
968 IN CONST UINT32 NodesStartOffset,
969 IN CONST CM_ARM_NAMED_COMPONENT_NODE *NodeList,
970 IN UINT32 NodeCount
971 )
972 {
973 EFI_STATUS Status;
974 EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE *NcNode;
975 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;
976 CHAR8 *ObjectName;
977 UINTN ObjectNameLength;
978 UINT64 NodeLength;
979
980 ASSERT (Iort != NULL);
981
982 NcNode = (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE *)((UINT8 *)Iort +
983 NodesStartOffset);
984
985 while (NodeCount-- != 0) {
986 NodeLength = GetNamedComponentNodeSize (NodeList);
987 if (NodeLength > MAX_UINT16) {
988 Status = EFI_INVALID_PARAMETER;
989 DEBUG ((
990 DEBUG_ERROR,
991 "ERROR: IORT: Named Component Node length 0x%lx > MAX_UINT16."
992 " Status = %r\n",
993 NodeLength,
994 Status
995 ));
996 return Status;
997 }
998
999 // Populate the node header
1000 NcNode->Node.Type = EFI_ACPI_IORT_TYPE_NAMED_COMP;
1001 NcNode->Node.Length = (UINT16)NodeLength;
1002 NcNode->Node.NumIdMappings = NodeList->IdMappingCount;
1003
1004 if (AcpiTableInfo->AcpiTableRevision <
1005 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
1006 {
1007 NcNode->Node.Revision = 2;
1008 NcNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
1009 } else {
1010 NcNode->Node.Revision = 4;
1011 NcNode->Node.Identifier = NodeList->Identifier;
1012 }
1013
1014 ObjectNameLength = AsciiStrLen (NodeList->ObjectName) + 1;
1015 NcNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?
1016 0 : ((UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE) +
1017 (ALIGN_VALUE (ObjectNameLength, 4))));
1018
1019 // Named Component specific data
1020 NcNode->Flags = NodeList->Flags;
1021 NcNode->CacheCoherent = NodeList->CacheCoherent;
1022 NcNode->AllocationHints = NodeList->AllocationHints;
1023 NcNode->Reserved = EFI_ACPI_RESERVED_WORD;
1024 NcNode->MemoryAccessFlags = NodeList->MemoryAccessFlags;
1025 NcNode->AddressSizeLimit = NodeList->AddressSizeLimit;
1026
1027 // Copy the object name
1028 ObjectName = (CHAR8 *)((UINT8 *)NcNode +
1029 sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE));
1030 Status = AsciiStrCpyS (
1031 ObjectName,
1032 ObjectNameLength,
1033 NodeList->ObjectName
1034 );
1035 if (EFI_ERROR (Status)) {
1036 DEBUG ((
1037 DEBUG_ERROR,
1038 "ERROR: IORT: Failed to copy Object Name. Status = %r\n",
1039 Status
1040 ));
1041 return Status;
1042 }
1043
1044 if (NodeList->IdMappingCount > 0) {
1045 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {
1046 Status = EFI_INVALID_PARAMETER;
1047 DEBUG ((
1048 DEBUG_ERROR,
1049 "ERROR: IORT: Invalid Id Mapping token,"
1050 " Token = 0x%x, Status =%r\n",
1051 NodeList->IdMappingToken,
1052 Status
1053 ));
1054 return Status;
1055 }
1056
1057 // Ids for Named Component
1058 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)NcNode +
1059 NcNode->Node.IdReference);
1060
1061 Status = AddIdMappingArray (
1062 This,
1063 CfgMgrProtocol,
1064 IdMapArray,
1065 NodeList->IdMappingCount,
1066 NodeList->IdMappingToken
1067 );
1068 if (EFI_ERROR (Status)) {
1069 DEBUG ((
1070 DEBUG_ERROR,
1071 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1072 Status
1073 ));
1074 return Status;
1075 }
1076 }
1077
1078 // Next Named Component Node
1079 NcNode = (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE *)((UINT8 *)NcNode +
1080 NcNode->Node.Length);
1081 NodeList++;
1082 } // Named Component Node
1083
1084 return EFI_SUCCESS;
1085 }
1086
1087 /** Update the Root Complex Node Information.
1088
1089 This function updates the Root Complex node information in the IORT table.
1090
1091 @param [in] This Pointer to the table Generator.
1092 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1093 Protocol Interface.
1094 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
1095 @param [in] Iort Pointer to IORT table structure.
1096 @param [in] NodesStartOffset Offset for the start of the Root Complex
1097 Nodes.
1098 @param [in] NodeList Pointer to an array of Root Complex Node
1099 Objects.
1100 @param [in] NodeCount Number of Root Complex Node Objects.
1101
1102 @retval EFI_SUCCESS Table generated successfully.
1103 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1104 @retval EFI_NOT_FOUND The required object was not found.
1105 **/
1106 STATIC
1107 EFI_STATUS
1108 AddRootComplexNodes (
1109 IN CONST ACPI_TABLE_GENERATOR *CONST This,
1110 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
1111 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
1112 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,
1113 IN CONST UINT32 NodesStartOffset,
1114 IN CONST CM_ARM_ROOT_COMPLEX_NODE *NodeList,
1115 IN UINT32 NodeCount
1116 )
1117 {
1118 EFI_STATUS Status;
1119 EFI_ACPI_6_0_IO_REMAPPING_RC_NODE *RcNode;
1120 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;
1121 UINT64 NodeLength;
1122
1123 ASSERT (Iort != NULL);
1124
1125 RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE *)((UINT8 *)Iort +
1126 NodesStartOffset);
1127
1128 while (NodeCount-- != 0) {
1129 NodeLength = GetRootComplexNodeSize (NodeList);
1130 if (NodeLength > MAX_UINT16) {
1131 Status = EFI_INVALID_PARAMETER;
1132 DEBUG ((
1133 DEBUG_ERROR,
1134 "ERROR: IORT: Root Complex Node length 0x%lx > MAX_UINT16."
1135 " Status = %r\n",
1136 NodeLength,
1137 Status
1138 ));
1139 return Status;
1140 }
1141
1142 // Populate the node header
1143 RcNode->Node.Type = EFI_ACPI_IORT_TYPE_ROOT_COMPLEX;
1144 RcNode->Node.Length = (UINT16)NodeLength;
1145 RcNode->Node.NumIdMappings = NodeList->IdMappingCount;
1146 RcNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?
1147 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE);
1148
1149 if (AcpiTableInfo->AcpiTableRevision <
1150 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
1151 {
1152 RcNode->Node.Revision = 1;
1153 RcNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
1154 RcNode->PasidCapabilities = EFI_ACPI_RESERVED_WORD;
1155 } else {
1156 RcNode->Node.Revision = 4;
1157 RcNode->Node.Identifier = NodeList->Identifier;
1158 RcNode->PasidCapabilities = NodeList->PasidCapabilities;
1159 RcNode->Flags = NodeList->Flags;
1160 }
1161
1162 // Root Complex specific data
1163 RcNode->CacheCoherent = NodeList->CacheCoherent;
1164 RcNode->AllocationHints = NodeList->AllocationHints;
1165 RcNode->Reserved = EFI_ACPI_RESERVED_WORD;
1166 RcNode->MemoryAccessFlags = NodeList->MemoryAccessFlags;
1167 RcNode->AtsAttribute = NodeList->AtsAttribute;
1168 RcNode->PciSegmentNumber = NodeList->PciSegmentNumber;
1169 RcNode->MemoryAddressSize = NodeList->MemoryAddressSize;
1170 RcNode->Reserved1[0] = EFI_ACPI_RESERVED_BYTE;
1171
1172 if (NodeList->IdMappingCount > 0) {
1173 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {
1174 Status = EFI_INVALID_PARAMETER;
1175 DEBUG ((
1176 DEBUG_ERROR,
1177 "ERROR: IORT: Invalid Id Mapping token,"
1178 " Token = 0x%x, Status =%r\n",
1179 NodeList->IdMappingToken,
1180 Status
1181 ));
1182 return Status;
1183 }
1184
1185 // Ids for Root Complex
1186 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)RcNode +
1187 RcNode->Node.IdReference);
1188 Status = AddIdMappingArray (
1189 This,
1190 CfgMgrProtocol,
1191 IdMapArray,
1192 NodeList->IdMappingCount,
1193 NodeList->IdMappingToken
1194 );
1195 if (EFI_ERROR (Status)) {
1196 DEBUG ((
1197 DEBUG_ERROR,
1198 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1199 Status
1200 ));
1201 return Status;
1202 }
1203 }
1204
1205 // Next Root Complex Node
1206 RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE *)((UINT8 *)RcNode +
1207 RcNode->Node.Length);
1208 NodeList++;
1209 } // Root Complex Node
1210
1211 return EFI_SUCCESS;
1212 }
1213
1214 /** Update the SMMU Interrupt Array.
1215
1216 This function retrieves the InterruptArray object referenced by the
1217 InterruptToken and updates the SMMU InterruptArray.
1218
1219 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1220 Protocol Interface.
1221 @param [in, out] InterruptArray Pointer to an array of Interrupts.
1222 @param [in] InterruptCount Number of entries in the InterruptArray.
1223 @param [in] InterruptToken Reference Token for retrieving the SMMU
1224 InterruptArray object.
1225
1226 @retval EFI_SUCCESS Table generated successfully.
1227 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1228 @retval EFI_NOT_FOUND The required object was not found.
1229 **/
1230 STATIC
1231 EFI_STATUS
1232 AddSmmuInterruptArray (
1233 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
1234 IN OUT EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *InterruptArray,
1235 IN UINT32 InterruptCount,
1236 IN CONST CM_OBJECT_TOKEN InterruptToken
1237 )
1238 {
1239 EFI_STATUS Status;
1240 CM_ARM_SMMU_INTERRUPT *SmmuInterrupt;
1241 UINT32 SmmuInterruptCount;
1242
1243 ASSERT (InterruptArray != NULL);
1244
1245 // Get the SMMU Interrupt Array
1246 Status = GetEArmObjSmmuInterruptArray (
1247 CfgMgrProtocol,
1248 InterruptToken,
1249 &SmmuInterrupt,
1250 &SmmuInterruptCount
1251 );
1252 if (EFI_ERROR (Status)) {
1253 DEBUG ((
1254 DEBUG_ERROR,
1255 "ERROR: IORT: Failed to get SMMU Interrupt array. Status = %r\n",
1256 Status
1257 ));
1258 return Status;
1259 }
1260
1261 if (SmmuInterruptCount < InterruptCount) {
1262 DEBUG ((
1263 DEBUG_ERROR,
1264 "ERROR: IORT: Failed to get the required number of SMMU Interrupts.\n"
1265 ));
1266 return EFI_NOT_FOUND;
1267 }
1268
1269 // Populate the Id Mapping array
1270 while (InterruptCount-- != 0) {
1271 InterruptArray->Interrupt = SmmuInterrupt->Interrupt;
1272 InterruptArray->InterruptFlags = SmmuInterrupt->Flags;
1273 InterruptArray++;
1274 SmmuInterrupt++;
1275 } // Id Mapping array
1276
1277 return EFI_SUCCESS;
1278 }
1279
1280 /** Update the SMMU v1/v2 Node Information.
1281
1282 @param [in] This Pointer to the table Generator.
1283 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1284 Protocol Interface.
1285 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
1286 @param [in] Iort Pointer to IORT table structure.
1287 @param [in] NodesStartOffset Offset for the start of the SMMU v1/v2
1288 Nodes.
1289 @param [in] NodeList Pointer to an array of SMMU v1/v2 Node
1290 Objects.
1291 @param [in] NodeCount Number of SMMU v1/v2 Node Objects.
1292
1293 @retval EFI_SUCCESS Table generated successfully.
1294 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1295 @retval EFI_NOT_FOUND The required object was not found.
1296 **/
1297 STATIC
1298 EFI_STATUS
1299 AddSmmuV1V2Nodes (
1300 IN CONST ACPI_TABLE_GENERATOR *CONST This,
1301 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
1302 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
1303 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,
1304 IN CONST UINT32 NodesStartOffset,
1305 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE *NodeList,
1306 IN UINT32 NodeCount
1307 )
1308 {
1309 EFI_STATUS Status;
1310 EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE *SmmuNode;
1311 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;
1312
1313 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *ContextInterruptArray;
1314 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *PmuInterruptArray;
1315 UINT64 NodeLength;
1316 UINT32 Offset;
1317
1318 ASSERT (Iort != NULL);
1319
1320 SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE *)((UINT8 *)Iort +
1321 NodesStartOffset);
1322
1323 while (NodeCount-- != 0) {
1324 NodeLength = GetSmmuV1V2NodeSize (NodeList);
1325 if (NodeLength > MAX_UINT16) {
1326 Status = EFI_INVALID_PARAMETER;
1327 DEBUG ((
1328 DEBUG_ERROR,
1329 "ERROR: IORT: SMMU V1/V2 Node length 0x%lx > MAX_UINT16. Status = %r\n",
1330 NodeLength,
1331 Status
1332 ));
1333 return Status;
1334 }
1335
1336 // Populate the node header
1337 SmmuNode->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv1v2;
1338 SmmuNode->Node.Length = (UINT16)NodeLength;
1339 SmmuNode->Node.NumIdMappings = NodeList->IdMappingCount;
1340 SmmuNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?
1341 0 : (sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE) +
1342 (NodeList->ContextInterruptCount *
1343 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)) +
1344 (NodeList->PmuInterruptCount *
1345 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)));
1346
1347 if (AcpiTableInfo->AcpiTableRevision <
1348 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
1349 {
1350 SmmuNode->Node.Revision = 1;
1351 SmmuNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
1352 } else {
1353 SmmuNode->Node.Revision = 3;
1354 SmmuNode->Node.Identifier = NodeList->Identifier;
1355 }
1356
1357 // SMMU v1/v2 specific data
1358 SmmuNode->Base = NodeList->BaseAddress;
1359 SmmuNode->Span = NodeList->Span;
1360 SmmuNode->Model = NodeList->Model;
1361 SmmuNode->Flags = NodeList->Flags;
1362
1363 // Reference to Global Interrupt Array
1364 SmmuNode->GlobalInterruptArrayRef =
1365 OFFSET_OF (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE, SMMU_NSgIrpt);
1366
1367 Offset = sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE);
1368 // Context Interrupt
1369 SmmuNode->NumContextInterrupts = NodeList->ContextInterruptCount;
1370 if (NodeList->ContextInterruptCount != 0) {
1371 SmmuNode->ContextInterruptArrayRef = Offset;
1372 ContextInterruptArray =
1373 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *)((UINT8 *)SmmuNode + Offset);
1374 Offset += (NodeList->ContextInterruptCount *
1375 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));
1376 }
1377
1378 // PMU Interrupt
1379 SmmuNode->NumPmuInterrupts = NodeList->PmuInterruptCount;
1380 if (NodeList->PmuInterruptCount != 0) {
1381 SmmuNode->PmuInterruptArrayRef = Offset;
1382 PmuInterruptArray =
1383 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *)((UINT8 *)SmmuNode + Offset);
1384 }
1385
1386 SmmuNode->SMMU_NSgIrpt = NodeList->SMMU_NSgIrpt;
1387 SmmuNode->SMMU_NSgIrptFlags = NodeList->SMMU_NSgIrptFlags;
1388 SmmuNode->SMMU_NSgCfgIrpt = NodeList->SMMU_NSgCfgIrpt;
1389 SmmuNode->SMMU_NSgCfgIrptFlags = NodeList->SMMU_NSgCfgIrptFlags;
1390
1391 if (NodeList->ContextInterruptCount != 0) {
1392 if (NodeList->ContextInterruptToken == CM_NULL_TOKEN) {
1393 Status = EFI_INVALID_PARAMETER;
1394 DEBUG ((
1395 DEBUG_ERROR,
1396 "ERROR: IORT: Invalid Context Interrupt token,"
1397 " Token = 0x%x, Status =%r\n",
1398 NodeList->ContextInterruptToken,
1399 Status
1400 ));
1401 return Status;
1402 }
1403
1404 // Add Context Interrupt Array
1405 Status = AddSmmuInterruptArray (
1406 CfgMgrProtocol,
1407 ContextInterruptArray,
1408 SmmuNode->NumContextInterrupts,
1409 NodeList->ContextInterruptToken
1410 );
1411 if (EFI_ERROR (Status)) {
1412 DEBUG ((
1413 DEBUG_ERROR,
1414 "ERROR: IORT: Failed to Context Interrupt Array. Status = %r\n",
1415 Status
1416 ));
1417 return Status;
1418 }
1419 }
1420
1421 // Add PMU Interrupt Array
1422 if (SmmuNode->NumPmuInterrupts != 0) {
1423 if (NodeList->PmuInterruptToken == CM_NULL_TOKEN) {
1424 Status = EFI_INVALID_PARAMETER;
1425 DEBUG ((
1426 DEBUG_ERROR,
1427 "ERROR: IORT: Invalid PMU Interrupt token,"
1428 " Token = 0x%x, Status =%r\n",
1429 NodeList->PmuInterruptToken,
1430 Status
1431 ));
1432 return Status;
1433 }
1434
1435 Status = AddSmmuInterruptArray (
1436 CfgMgrProtocol,
1437 PmuInterruptArray,
1438 SmmuNode->NumPmuInterrupts,
1439 NodeList->PmuInterruptToken
1440 );
1441 if (EFI_ERROR (Status)) {
1442 DEBUG ((
1443 DEBUG_ERROR,
1444 "ERROR: IORT: Failed to PMU Interrupt Array. Status = %r\n",
1445 Status
1446 ));
1447 return Status;
1448 }
1449 }
1450
1451 if (NodeList->IdMappingCount > 0) {
1452 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {
1453 Status = EFI_INVALID_PARAMETER;
1454 DEBUG ((
1455 DEBUG_ERROR,
1456 "ERROR: IORT: Invalid Id Mapping token,"
1457 " Token = 0x%x, Status =%r\n",
1458 NodeList->IdMappingToken,
1459 Status
1460 ));
1461 return Status;
1462 }
1463
1464 // Ids for SMMU v1/v2 Node
1465 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)SmmuNode +
1466 SmmuNode->Node.IdReference);
1467 Status = AddIdMappingArray (
1468 This,
1469 CfgMgrProtocol,
1470 IdMapArray,
1471 NodeList->IdMappingCount,
1472 NodeList->IdMappingToken
1473 );
1474 if (EFI_ERROR (Status)) {
1475 DEBUG ((
1476 DEBUG_ERROR,
1477 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1478 Status
1479 ));
1480 return Status;
1481 }
1482 }
1483
1484 // Next SMMU v1/v2 Node
1485 SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE *)((UINT8 *)SmmuNode +
1486 SmmuNode->Node.Length);
1487 NodeList++;
1488 } // SMMU v1/v2 Node
1489
1490 return EFI_SUCCESS;
1491 }
1492
1493 /** Update the SMMUv3 Node Information.
1494
1495 This function updates the SMMUv3 node information in the IORT table.
1496
1497 @param [in] This Pointer to the table Generator.
1498 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1499 Protocol Interface.
1500 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
1501 @param [in] Iort Pointer to IORT table structure.
1502 @param [in] NodesStartOffset Offset for the start of the SMMUv3 Nodes.
1503 @param [in] NodeList Pointer to an array of SMMUv3 Node Objects.
1504 @param [in] NodeCount Number of SMMUv3 Node Objects.
1505
1506 @retval EFI_SUCCESS Table generated successfully.
1507 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1508 @retval EFI_NOT_FOUND The required object was not found.
1509 **/
1510 STATIC
1511 EFI_STATUS
1512 AddSmmuV3Nodes (
1513 IN CONST ACPI_TABLE_GENERATOR *CONST This,
1514 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
1515 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
1516 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,
1517 IN CONST UINT32 NodesStartOffset,
1518 IN CONST CM_ARM_SMMUV3_NODE *NodeList,
1519 IN UINT32 NodeCount
1520 )
1521 {
1522 EFI_STATUS Status;
1523 EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *SmmuV3Node;
1524 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;
1525 UINT64 NodeLength;
1526
1527 ASSERT (Iort != NULL);
1528
1529 SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *)((UINT8 *)Iort +
1530 NodesStartOffset);
1531
1532 while (NodeCount-- != 0) {
1533 NodeLength = GetSmmuV3NodeSize (NodeList);
1534 if (NodeLength > MAX_UINT16) {
1535 Status = EFI_INVALID_PARAMETER;
1536 DEBUG ((
1537 DEBUG_ERROR,
1538 "ERROR: IORT: SMMU V3 Node length 0x%lx > MAX_UINT16. Status = %r\n",
1539 NodeLength,
1540 Status
1541 ));
1542 return Status;
1543 }
1544
1545 // Populate the node header
1546 SmmuV3Node->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv3;
1547 SmmuV3Node->Node.Length = (UINT16)NodeLength;
1548 SmmuV3Node->Node.NumIdMappings = NodeList->IdMappingCount;
1549 SmmuV3Node->Node.IdReference = (NodeList->IdMappingCount == 0) ?
1550 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE);
1551
1552 if (AcpiTableInfo->AcpiTableRevision <
1553 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
1554 {
1555 SmmuV3Node->Node.Revision = 2;
1556 SmmuV3Node->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
1557 } else {
1558 SmmuV3Node->Node.Revision = 4;
1559 SmmuV3Node->Node.Identifier = NodeList->Identifier;
1560 }
1561
1562 // SMMUv3 specific data
1563 SmmuV3Node->Base = NodeList->BaseAddress;
1564 SmmuV3Node->Flags = NodeList->Flags;
1565 SmmuV3Node->Reserved = EFI_ACPI_RESERVED_WORD;
1566 SmmuV3Node->VatosAddress = NodeList->VatosAddress;
1567 SmmuV3Node->Model = NodeList->Model;
1568 SmmuV3Node->Event = NodeList->EventInterrupt;
1569 SmmuV3Node->Pri = NodeList->PriInterrupt;
1570 SmmuV3Node->Gerr = NodeList->GerrInterrupt;
1571 SmmuV3Node->Sync = NodeList->SyncInterrupt;
1572
1573 if ((SmmuV3Node->Flags & EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN) != 0) {
1574 // The Proximity Domain Valid flag is set to 1
1575 SmmuV3Node->ProximityDomain = NodeList->ProximityDomain;
1576 } else {
1577 SmmuV3Node->ProximityDomain = 0;
1578 }
1579
1580 if ((SmmuV3Node->Event != 0) && (SmmuV3Node->Pri != 0) &&
1581 (SmmuV3Node->Gerr != 0) && (SmmuV3Node->Sync != 0))
1582 {
1583 // If all the SMMU control interrupts are GSIV based,
1584 // the DeviceID mapping index field is ignored.
1585 SmmuV3Node->DeviceIdMappingIndex = 0;
1586 } else {
1587 SmmuV3Node->DeviceIdMappingIndex = NodeList->DeviceIdMappingIndex;
1588 }
1589
1590 if (NodeList->IdMappingCount > 0) {
1591 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {
1592 Status = EFI_INVALID_PARAMETER;
1593 DEBUG ((
1594 DEBUG_ERROR,
1595 "ERROR: IORT: Invalid Id Mapping token,"
1596 " Token = 0x%x, Status =%r\n",
1597 NodeList->IdMappingToken,
1598 Status
1599 ));
1600 return Status;
1601 }
1602
1603 // Ids for SMMUv3 node
1604 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)SmmuV3Node +
1605 SmmuV3Node->Node.IdReference);
1606 Status = AddIdMappingArray (
1607 This,
1608 CfgMgrProtocol,
1609 IdMapArray,
1610 NodeList->IdMappingCount,
1611 NodeList->IdMappingToken
1612 );
1613 if (EFI_ERROR (Status)) {
1614 DEBUG ((
1615 DEBUG_ERROR,
1616 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1617 Status
1618 ));
1619 return Status;
1620 }
1621 }
1622
1623 // Next SMMUv3 Node
1624 SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *)((UINT8 *)SmmuV3Node +
1625 SmmuV3Node->Node.Length);
1626 NodeList++;
1627 } // SMMUv3 Node
1628
1629 return EFI_SUCCESS;
1630 }
1631
1632 /** Update the PMCG Node Information.
1633
1634 This function updates the PMCG node information in the IORT table.
1635
1636 @param [in] This Pointer to the table Generator.
1637 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1638 Protocol Interface.
1639 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
1640 @param [in] Iort Pointer to IORT table structure.
1641 @param [in] NodesStartOffset Offset for the start of the PMCG Nodes.
1642 @param [in] NodeList Pointer to an array of PMCG Node Objects.
1643 @param [in] NodeCount Number of PMCG Node Objects.
1644
1645 @retval EFI_SUCCESS Table generated successfully.
1646 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1647 @retval EFI_NOT_FOUND The required object was not found.
1648 **/
1649 STATIC
1650 EFI_STATUS
1651 AddPmcgNodes (
1652 IN CONST ACPI_TABLE_GENERATOR *CONST This,
1653 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
1654 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
1655 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,
1656 IN CONST UINT32 NodesStartOffset,
1657 IN CONST CM_ARM_PMCG_NODE *NodeList,
1658 IN UINT32 NodeCount
1659 )
1660 {
1661 EFI_STATUS Status;
1662 EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE *PmcgNode;
1663 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;
1664 ACPI_IORT_GENERATOR *Generator;
1665 UINT64 NodeLength;
1666
1667 ASSERT (Iort != NULL);
1668
1669 Generator = (ACPI_IORT_GENERATOR *)This;
1670 PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE *)((UINT8 *)Iort +
1671 NodesStartOffset);
1672
1673 while (NodeCount-- != 0) {
1674 NodeLength = GetPmcgNodeSize (NodeList);
1675 if (NodeLength > MAX_UINT16) {
1676 Status = EFI_INVALID_PARAMETER;
1677 DEBUG ((
1678 DEBUG_ERROR,
1679 "ERROR: IORT: PMCG Node length 0x%lx > MAX_UINT16. Status = %r\n",
1680 NodeLength,
1681 Status
1682 ));
1683 return Status;
1684 }
1685
1686 // Populate the node header
1687 PmcgNode->Node.Type = EFI_ACPI_IORT_TYPE_PMCG;
1688 PmcgNode->Node.Length = (UINT16)NodeLength;
1689 PmcgNode->Node.NumIdMappings = NodeList->IdMappingCount;
1690 PmcgNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?
1691 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE);
1692
1693 if (AcpiTableInfo->AcpiTableRevision <
1694 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
1695 {
1696 PmcgNode->Node.Revision = 1;
1697 PmcgNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
1698 } else {
1699 PmcgNode->Node.Revision = 2;
1700 PmcgNode->Node.Identifier = NodeList->Identifier;
1701 }
1702
1703 // PMCG specific data
1704 PmcgNode->Base = NodeList->BaseAddress;
1705 PmcgNode->OverflowInterruptGsiv = NodeList->OverflowInterrupt;
1706 PmcgNode->Page1Base = NodeList->Page1BaseAddress;
1707
1708 Status = GetNodeOffsetReferencedByToken (
1709 Generator->NodeIndexer,
1710 Generator->IortNodeCount,
1711 NodeList->ReferenceToken,
1712 &PmcgNode->NodeReference
1713 );
1714 if (EFI_ERROR (Status)) {
1715 DEBUG ((
1716 DEBUG_ERROR,
1717 "ERROR: IORT: Failed to get Output Reference for PMCG Node."
1718 "Reference Token = %p"
1719 " Status = %r\n",
1720 NodeList->ReferenceToken,
1721 Status
1722 ));
1723 return Status;
1724 }
1725
1726 if (NodeList->IdMappingCount > 0) {
1727 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {
1728 Status = EFI_INVALID_PARAMETER;
1729 DEBUG ((
1730 DEBUG_ERROR,
1731 "ERROR: IORT: Invalid Id Mapping token,"
1732 " Token = 0x%x, Status =%r\n",
1733 NodeList->IdMappingToken,
1734 Status
1735 ));
1736 return Status;
1737 }
1738
1739 // Ids for PMCG node
1740 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)PmcgNode +
1741 PmcgNode->Node.IdReference);
1742
1743 Status = AddIdMappingArray (
1744 This,
1745 CfgMgrProtocol,
1746 IdMapArray,
1747 NodeList->IdMappingCount,
1748 NodeList->IdMappingToken
1749 );
1750 if (EFI_ERROR (Status)) {
1751 DEBUG ((
1752 DEBUG_ERROR,
1753 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1754 Status
1755 ));
1756 return Status;
1757 }
1758 }
1759
1760 // Next PMCG Node
1761 PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE *)((UINT8 *)PmcgNode +
1762 PmcgNode->Node.Length);
1763 NodeList++;
1764 } // PMCG Node
1765
1766 return EFI_SUCCESS;
1767 }
1768
1769 /** Update the Memory Range Descriptor Array.
1770
1771 This function retrieves the Memory Range Descriptor objects referenced by
1772 MemRangeDescToken and updates the Memory Range Descriptor array.
1773
1774 @param [in] This Pointer to the table Generator.
1775 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1776 Protocol Interface.
1777 @param [in] DescArray Pointer to an array of Memory Range
1778 Descriptors.
1779 @param [in] DescCount Number of Id Descriptors.
1780 @param [in] DescToken Reference Token for retrieving the
1781 Memory Range Descriptor Array.
1782
1783 @retval EFI_SUCCESS Table generated successfully.
1784 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1785 @retval EFI_NOT_FOUND The required object was not found.
1786 **/
1787 STATIC
1788 EFI_STATUS
1789 AddMemRangeDescArray (
1790 IN CONST ACPI_TABLE_GENERATOR *CONST This,
1791 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
1792 IN EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC *DescArray,
1793 IN UINT32 DescCount,
1794 IN CONST CM_OBJECT_TOKEN DescToken
1795 )
1796 {
1797 EFI_STATUS Status;
1798 CM_ARM_MEMORY_RANGE_DESCRIPTOR *MemRangeDesc;
1799 UINT32 MemRangeDescCount;
1800
1801 ASSERT (DescArray != NULL);
1802
1803 // Get the Id Mapping Array
1804 Status = GetEArmObjMemoryRangeDescriptor (
1805 CfgMgrProtocol,
1806 DescToken,
1807 &MemRangeDesc,
1808 &MemRangeDescCount
1809 );
1810 if (EFI_ERROR (Status)) {
1811 DEBUG ((
1812 DEBUG_ERROR,
1813 "ERROR: IORT: Failed to get Memory Range Descriptor array. Status = %r\n",
1814 Status
1815 ));
1816 return Status;
1817 }
1818
1819 if (MemRangeDescCount < DescCount) {
1820 DEBUG ((
1821 DEBUG_ERROR,
1822 "ERROR: IORT: Failed to get the required number of Memory"
1823 " Range Descriptors.\n"
1824 ));
1825 return EFI_NOT_FOUND;
1826 }
1827
1828 // Populate the Memory Range Descriptor array
1829 while (DescCount-- != 0) {
1830 DescArray->Base = MemRangeDesc->BaseAddress;
1831 DescArray->Length = MemRangeDesc->Length;
1832 DescArray->Reserved = EFI_ACPI_RESERVED_DWORD;
1833
1834 DescArray++;
1835 MemRangeDesc++;
1836 }
1837
1838 return EFI_SUCCESS;
1839 }
1840
1841 /** Update the RMR Node Information.
1842
1843 This function updates the RMR node information in the IORT table.
1844
1845 @param [in] This Pointer to the table Generator.
1846 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1847 Protocol Interface.
1848 @param [in] AcpiTableInfo Pointer to the ACPI table info structure.
1849 @param [in] Iort Pointer to IORT table structure.
1850 @param [in] NodesStartOffset Offset for the start of the PMCG Nodes.
1851 @param [in] NodeList Pointer to an array of PMCG Node Objects.
1852 @param [in] NodeCount Number of PMCG Node Objects.
1853
1854 @retval EFI_SUCCESS Table generated successfully.
1855 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1856 @retval EFI_NOT_FOUND The required object was not found.
1857 **/
1858 STATIC
1859 EFI_STATUS
1860 AddRmrNodes (
1861 IN CONST ACPI_TABLE_GENERATOR *CONST This,
1862 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
1863 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
1864 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,
1865 IN CONST UINT32 NodesStartOffset,
1866 IN CONST CM_ARM_RMR_NODE *NodeList,
1867 IN UINT32 NodeCount
1868 )
1869 {
1870 EFI_STATUS Status;
1871 EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE *RmrNode;
1872 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;
1873 EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC *MemRangeDescArray;
1874 UINT64 NodeLength;
1875
1876 ASSERT (Iort != NULL);
1877
1878 RmrNode = (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE *)((UINT8 *)Iort +
1879 NodesStartOffset);
1880
1881 while (NodeCount-- != 0) {
1882 NodeLength = GetRmrNodeSize (NodeList);
1883 if (NodeLength > MAX_UINT16) {
1884 Status = EFI_INVALID_PARAMETER;
1885 DEBUG ((
1886 DEBUG_ERROR,
1887 "ERROR: IORT: RMR Node length 0x%lx > MAX_UINT16. Status = %r\n",
1888 NodeLength,
1889 Status
1890 ));
1891 return Status;
1892 }
1893
1894 if (NodeList->MemRangeDescCount == 0) {
1895 Status = EFI_INVALID_PARAMETER;
1896 DEBUG ((
1897 DEBUG_ERROR,
1898 "ERROR: IORT: Memory Range Desc count = %d. Status = %r\n",
1899 NodeList->MemRangeDescCount,
1900 Status
1901 ));
1902 return Status;
1903 }
1904
1905 if (NodeList->MemRangeDescToken == CM_NULL_TOKEN) {
1906 Status = EFI_INVALID_PARAMETER;
1907 DEBUG ((
1908 DEBUG_ERROR,
1909 "ERROR: IORT: Invalid Memory Range Descriptor token,"
1910 " Token = 0x%x. Status = %r\n",
1911 NodeList->MemRangeDescToken,
1912 Status
1913 ));
1914 return Status;
1915 }
1916
1917 // Populate the node header
1918 RmrNode->Node.Type = EFI_ACPI_IORT_TYPE_RMR;
1919 RmrNode->Node.Length = (UINT16)NodeLength;
1920 RmrNode->Node.Revision = 3;
1921 RmrNode->Node.Identifier = NodeList->Identifier;
1922 RmrNode->Node.NumIdMappings = NodeList->IdMappingCount;
1923 RmrNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?
1924 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE);
1925
1926 // RMR specific data
1927 RmrNode->Flags = NodeList->Flags;
1928 RmrNode->NumMemRangeDesc = NodeList->MemRangeDescCount;
1929 RmrNode->MemRangeDescRef = (NodeList->MemRangeDescCount == 0) ?
1930 0 : (sizeof (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE) +
1931 (NodeList->IdMappingCount *
1932 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)));
1933
1934 if (NodeList->IdMappingCount > 0) {
1935 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {
1936 Status = EFI_INVALID_PARAMETER;
1937 DEBUG ((
1938 DEBUG_ERROR,
1939 "ERROR: IORT: Invalid Id Mapping token,"
1940 " Token = 0x%x, Status =%r\n",
1941 NodeList->IdMappingToken,
1942 Status
1943 ));
1944 return Status;
1945 }
1946
1947 // Ids for RMR node
1948 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)RmrNode +
1949 RmrNode->Node.IdReference);
1950
1951 Status = AddIdMappingArray (
1952 This,
1953 CfgMgrProtocol,
1954 IdMapArray,
1955 NodeList->IdMappingCount,
1956 NodeList->IdMappingToken
1957 );
1958 if (EFI_ERROR (Status)) {
1959 DEBUG ((
1960 DEBUG_ERROR,
1961 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
1962 Status
1963 ));
1964 return Status;
1965 }
1966 }
1967
1968 // Memory Range Descriptors for RMR node
1969 MemRangeDescArray = (EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC *)(
1970 (UINT8 *)RmrNode +
1971 RmrNode->MemRangeDescRef
1972 );
1973
1974 Status = AddMemRangeDescArray (
1975 This,
1976 CfgMgrProtocol,
1977 MemRangeDescArray,
1978 NodeList->MemRangeDescCount,
1979 NodeList->MemRangeDescToken
1980 );
1981 if (EFI_ERROR (Status)) {
1982 DEBUG ((
1983 DEBUG_ERROR,
1984 "ERROR: IORT: Failed to Memory Range Descriptor Array. Status = %r\n",
1985 Status
1986 ));
1987 return Status;
1988 }
1989
1990 // Next RMR Node
1991 RmrNode = (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE *)((UINT8 *)RmrNode +
1992 RmrNode->Node.Length);
1993 NodeList++;
1994 } // RMR Node
1995
1996 return EFI_SUCCESS;
1997 }
1998
1999 /** Validates that the IORT nodes Identifier are unique.
2000
2001 @param [in] NodeIndexer Pointer to the Node Indexer.
2002 @param [in] NodeCount Number of IORT Nodes.
2003
2004 @retval EFI_SUCCESS Success.
2005 @retval EFI_INVALID_PARAMETER Identifier field not unique.
2006 **/
2007 STATIC
2008 EFI_STATUS
2009 ValidateNodeIdentifiers (
2010 IN CONST IORT_NODE_INDEXER *CONST NodeIndexer,
2011 IN UINT32 NodeCount
2012 )
2013 {
2014 UINT32 IndexI;
2015 UINT32 IndexJ;
2016
2017 for (IndexI = 0; IndexI < NodeCount; IndexI++) {
2018 for (IndexJ = 0; IndexJ < NodeCount; IndexJ++) {
2019 if ((IndexI != IndexJ) &&
2020 (NodeIndexer[IndexI].Identifier == NodeIndexer[IndexJ].Identifier))
2021 {
2022 DEBUG ((
2023 DEBUG_ERROR,
2024 "ERROR: IORT: UID %d of Token %p matches with that of Token %p.\n",
2025 NodeIndexer[IndexI].Identifier,
2026 NodeIndexer[IndexI].Token,
2027 NodeIndexer[IndexJ].Token
2028 ));
2029 return EFI_INVALID_PARAMETER;
2030 }
2031 }// IndexJ
2032 } // IndexI
2033
2034 return EFI_SUCCESS;
2035 }
2036
2037 /** Construct the IORT ACPI table.
2038
2039 This function invokes the Configuration Manager protocol interface
2040 to get the required hardware information for generating the ACPI
2041 table.
2042
2043 If this function allocates any resources then they must be freed
2044 in the FreeXXXXTableResources function.
2045
2046 @param [in] This Pointer to the table generator.
2047 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
2048 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
2049 Protocol Interface.
2050 @param [out] Table Pointer to the constructed ACPI Table.
2051
2052 @retval EFI_SUCCESS Table generated successfully.
2053 @retval EFI_INVALID_PARAMETER A parameter is invalid.
2054 @retval EFI_NOT_FOUND The required object was not found.
2055 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
2056 Manager is less than the Object size for the
2057 requested object.
2058 **/
2059 STATIC
2060 EFI_STATUS
2061 EFIAPI
2062 BuildIortTable (
2063 IN CONST ACPI_TABLE_GENERATOR *CONST This,
2064 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
2065 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
2066 OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table
2067 )
2068 {
2069 EFI_STATUS Status;
2070
2071 UINT64 TableSize;
2072 UINT64 NodeSize;
2073
2074 UINT32 IortNodeCount;
2075 UINT32 ItsGroupNodeCount;
2076 UINT32 NamedComponentNodeCount;
2077 UINT32 RootComplexNodeCount;
2078 UINT32 SmmuV1V2NodeCount;
2079 UINT32 SmmuV3NodeCount;
2080 UINT32 PmcgNodeCount;
2081 UINT32 RmrNodeCount;
2082
2083 UINT32 ItsGroupOffset;
2084 UINT32 NamedComponentOffset;
2085 UINT32 RootComplexOffset;
2086 UINT32 SmmuV1V2Offset;
2087 UINT32 SmmuV3Offset;
2088 UINT32 PmcgOffset;
2089 UINT32 RmrOffset;
2090
2091 CM_ARM_ITS_GROUP_NODE *ItsGroupNodeList;
2092 CM_ARM_NAMED_COMPONENT_NODE *NamedComponentNodeList;
2093 CM_ARM_ROOT_COMPLEX_NODE *RootComplexNodeList;
2094 CM_ARM_SMMUV1_SMMUV2_NODE *SmmuV1V2NodeList;
2095 CM_ARM_SMMUV3_NODE *SmmuV3NodeList;
2096 CM_ARM_PMCG_NODE *PmcgNodeList;
2097 CM_ARM_RMR_NODE *RmrNodeList;
2098
2099 EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort;
2100 IORT_NODE_INDEXER *NodeIndexer;
2101 ACPI_IORT_GENERATOR *Generator;
2102
2103 ASSERT (This != NULL);
2104 ASSERT (AcpiTableInfo != NULL);
2105 ASSERT (CfgMgrProtocol != NULL);
2106 ASSERT (Table != NULL);
2107 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
2108 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
2109
2110 RmrNodeCount = 0;
2111
2112 if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
2113 (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision))
2114 {
2115 DEBUG ((
2116 DEBUG_ERROR,
2117 "ERROR: IORT: Requested table revision = %d, is not supported."
2118 "Supported table revision: Minimum = %d, Maximum = %d\n",
2119 AcpiTableInfo->AcpiTableRevision,
2120 This->MinAcpiTableRevision,
2121 This->AcpiTableRevision
2122 ));
2123 return EFI_INVALID_PARAMETER;
2124 }
2125
2126 if ((AcpiTableInfo->AcpiTableRevision > EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00) &&
2127 (AcpiTableInfo->AcpiTableRevision < EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05))
2128 {
2129 DEBUG ((
2130 DEBUG_ERROR,
2131 "ERROR: IORT: Revisions E (1), E.a(2),b(3),c(4) are not supported.\n"
2132 ));
2133 return EFI_INVALID_PARAMETER;
2134 }
2135
2136 Generator = (ACPI_IORT_GENERATOR *)This;
2137 *Table = NULL;
2138
2139 // Get the ITS group node info
2140 Status = GetEArmObjItsGroup (
2141 CfgMgrProtocol,
2142 CM_NULL_TOKEN,
2143 &ItsGroupNodeList,
2144 &ItsGroupNodeCount
2145 );
2146 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
2147 DEBUG ((
2148 DEBUG_ERROR,
2149 "ERROR: IORT: Failed to get ITS Group Node Info. Status = %r\n",
2150 Status
2151 ));
2152 goto error_handler;
2153 }
2154
2155 // Add the ITS group node count
2156 IortNodeCount = ItsGroupNodeCount;
2157
2158 // Get the Named component node info
2159 Status = GetEArmObjNamedComponent (
2160 CfgMgrProtocol,
2161 CM_NULL_TOKEN,
2162 &NamedComponentNodeList,
2163 &NamedComponentNodeCount
2164 );
2165 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
2166 DEBUG ((
2167 DEBUG_ERROR,
2168 "ERROR: IORT: Failed to get Named Component Node Info. Status = %r\n",
2169 Status
2170 ));
2171 goto error_handler;
2172 }
2173
2174 // Add the Named Component group count
2175 IortNodeCount += NamedComponentNodeCount;
2176
2177 // Get the Root complex node info
2178 Status = GetEArmObjRootComplex (
2179 CfgMgrProtocol,
2180 CM_NULL_TOKEN,
2181 &RootComplexNodeList,
2182 &RootComplexNodeCount
2183 );
2184 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
2185 DEBUG ((
2186 DEBUG_ERROR,
2187 "ERROR: IORT: Failed to get Root Complex Node Info. Status = %r\n",
2188 Status
2189 ));
2190 goto error_handler;
2191 }
2192
2193 // Add the Root Complex node count
2194 IortNodeCount += RootComplexNodeCount;
2195
2196 // Get the SMMU v1/v2 node info
2197 Status = GetEArmObjSmmuV1SmmuV2 (
2198 CfgMgrProtocol,
2199 CM_NULL_TOKEN,
2200 &SmmuV1V2NodeList,
2201 &SmmuV1V2NodeCount
2202 );
2203 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
2204 DEBUG ((
2205 DEBUG_ERROR,
2206 "ERROR: IORT: Failed to get SMMUv1/SMMUv2 Node Info. Status = %r\n",
2207 Status
2208 ));
2209 goto error_handler;
2210 }
2211
2212 // Add the SMMU v1/v2 node count
2213 IortNodeCount += SmmuV1V2NodeCount;
2214
2215 // Get the SMMUv3 node info
2216 Status = GetEArmObjSmmuV3 (
2217 CfgMgrProtocol,
2218 CM_NULL_TOKEN,
2219 &SmmuV3NodeList,
2220 &SmmuV3NodeCount
2221 );
2222 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
2223 DEBUG ((
2224 DEBUG_ERROR,
2225 "ERROR: IORT: Failed to get SMMUv3 Node Info. Status = %r\n",
2226 Status
2227 ));
2228 goto error_handler;
2229 }
2230
2231 // Add the SMMUv3 node count
2232 IortNodeCount += SmmuV3NodeCount;
2233
2234 // Get the PMCG node info
2235 Status = GetEArmObjPmcg (
2236 CfgMgrProtocol,
2237 CM_NULL_TOKEN,
2238 &PmcgNodeList,
2239 &PmcgNodeCount
2240 );
2241 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
2242 DEBUG ((
2243 DEBUG_ERROR,
2244 "ERROR: IORT: Failed to get PMCG Node Info. Status = %r\n",
2245 Status
2246 ));
2247 goto error_handler;
2248 }
2249
2250 // Add the PMCG node count
2251 IortNodeCount += PmcgNodeCount;
2252
2253 if (AcpiTableInfo->AcpiTableRevision >=
2254 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
2255 {
2256 // Get the RMR node info
2257 Status = GetEArmObjRmr (
2258 CfgMgrProtocol,
2259 CM_NULL_TOKEN,
2260 &RmrNodeList,
2261 &RmrNodeCount
2262 );
2263 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
2264 DEBUG ((
2265 DEBUG_ERROR,
2266 "ERROR: IORT: Failed to get RMR Node Info. Status = %r\n",
2267 Status
2268 ));
2269 goto error_handler;
2270 }
2271
2272 // Add the RMR node count
2273 IortNodeCount += RmrNodeCount;
2274 }
2275
2276 // Allocate Node Indexer array
2277 NodeIndexer = (IORT_NODE_INDEXER *)AllocateZeroPool (
2278 (sizeof (IORT_NODE_INDEXER) *
2279 IortNodeCount)
2280 );
2281 if (NodeIndexer == NULL) {
2282 Status = EFI_OUT_OF_RESOURCES;
2283 DEBUG ((
2284 DEBUG_ERROR,
2285 "ERROR: IORT: Failed to allocate memory for Node Indexer" \
2286 " Status = %r\n",
2287 Status
2288 ));
2289 goto error_handler;
2290 }
2291
2292 DEBUG ((DEBUG_INFO, "INFO: NodeIndexer = %p\n", NodeIndexer));
2293 Generator->IortNodeCount = IortNodeCount;
2294 Generator->NodeIndexer = NodeIndexer;
2295
2296 // Calculate the size of the IORT table
2297 TableSize = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);
2298
2299 // ITS Group Nodes
2300 if (ItsGroupNodeCount > 0) {
2301 ItsGroupOffset = (UINT32)TableSize;
2302 // Size of ITS Group node list.
2303 NodeSize = GetSizeofItsGroupNodes (
2304 ItsGroupOffset,
2305 ItsGroupNodeList,
2306 ItsGroupNodeCount,
2307 &NodeIndexer
2308 );
2309 if (NodeSize > MAX_UINT32) {
2310 Status = EFI_INVALID_PARAMETER;
2311 DEBUG ((
2312 DEBUG_ERROR,
2313 "ERROR: IORT: Invalid Size of Group Nodes. Status = %r\n",
2314 Status
2315 ));
2316 goto error_handler;
2317 }
2318
2319 TableSize += NodeSize;
2320
2321 DEBUG ((
2322 DEBUG_INFO,
2323 " ItsGroupNodeCount = %d\n" \
2324 " ItsGroupOffset = %d\n",
2325 ItsGroupNodeCount,
2326 ItsGroupOffset
2327 ));
2328 }
2329
2330 // Named Component Nodes
2331 if (NamedComponentNodeCount > 0) {
2332 NamedComponentOffset = (UINT32)TableSize;
2333 // Size of Named Component node list.
2334 NodeSize = GetSizeofNamedComponentNodes (
2335 NamedComponentOffset,
2336 NamedComponentNodeList,
2337 NamedComponentNodeCount,
2338 &NodeIndexer
2339 );
2340 if (NodeSize > MAX_UINT32) {
2341 Status = EFI_INVALID_PARAMETER;
2342 DEBUG ((
2343 DEBUG_ERROR,
2344 "ERROR: IORT: Invalid Size of Named Component Nodes. Status = %r\n",
2345 Status
2346 ));
2347 goto error_handler;
2348 }
2349
2350 TableSize += NodeSize;
2351
2352 DEBUG ((
2353 DEBUG_INFO,
2354 " NamedComponentNodeCount = %d\n" \
2355 " NamedComponentOffset = %d\n",
2356 NamedComponentNodeCount,
2357 NamedComponentOffset
2358 ));
2359 }
2360
2361 // Root Complex Nodes
2362 if (RootComplexNodeCount > 0) {
2363 RootComplexOffset = (UINT32)TableSize;
2364 // Size of Root Complex node list.
2365 NodeSize = GetSizeofRootComplexNodes (
2366 RootComplexOffset,
2367 RootComplexNodeList,
2368 RootComplexNodeCount,
2369 &NodeIndexer
2370 );
2371 if (NodeSize > MAX_UINT32) {
2372 Status = EFI_INVALID_PARAMETER;
2373 DEBUG ((
2374 DEBUG_ERROR,
2375 "ERROR: IORT: Invalid Size of Root Complex Nodes. Status = %r\n",
2376 Status
2377 ));
2378 goto error_handler;
2379 }
2380
2381 TableSize += NodeSize;
2382
2383 DEBUG ((
2384 DEBUG_INFO,
2385 " RootComplexNodeCount = %d\n" \
2386 " RootComplexOffset = %d\n",
2387 RootComplexNodeCount,
2388 RootComplexOffset
2389 ));
2390 }
2391
2392 // SMMUv1/SMMUv2 Nodes
2393 if (SmmuV1V2NodeCount > 0) {
2394 SmmuV1V2Offset = (UINT32)TableSize;
2395 // Size of SMMUv1/SMMUv2 node list.
2396 NodeSize = GetSizeofSmmuV1V2Nodes (
2397 SmmuV1V2Offset,
2398 SmmuV1V2NodeList,
2399 SmmuV1V2NodeCount,
2400 &NodeIndexer
2401 );
2402 if (NodeSize > MAX_UINT32) {
2403 Status = EFI_INVALID_PARAMETER;
2404 DEBUG ((
2405 DEBUG_ERROR,
2406 "ERROR: IORT: Invalid Size of SMMUv1/v2 Nodes. Status = %r\n",
2407 Status
2408 ));
2409 goto error_handler;
2410 }
2411
2412 TableSize += NodeSize;
2413
2414 DEBUG ((
2415 DEBUG_INFO,
2416 " SmmuV1V2NodeCount = %d\n" \
2417 " SmmuV1V2Offset = %d\n",
2418 SmmuV1V2NodeCount,
2419 SmmuV1V2Offset
2420 ));
2421 }
2422
2423 // SMMUv3 Nodes
2424 if (SmmuV3NodeCount > 0) {
2425 SmmuV3Offset = (UINT32)TableSize;
2426 // Size of SMMUv3 node list.
2427 NodeSize = GetSizeofSmmuV3Nodes (
2428 SmmuV3Offset,
2429 SmmuV3NodeList,
2430 SmmuV3NodeCount,
2431 &NodeIndexer
2432 );
2433 if (NodeSize > MAX_UINT32) {
2434 Status = EFI_INVALID_PARAMETER;
2435 DEBUG ((
2436 DEBUG_ERROR,
2437 "ERROR: IORT: Invalid Size of SMMUv3 Nodes. Status = %r\n",
2438 Status
2439 ));
2440 goto error_handler;
2441 }
2442
2443 TableSize += NodeSize;
2444
2445 DEBUG ((
2446 DEBUG_INFO,
2447 " SmmuV3NodeCount = %d\n" \
2448 " SmmuV3Offset = %d\n",
2449 SmmuV3NodeCount,
2450 SmmuV3Offset
2451 ));
2452 }
2453
2454 // PMCG Nodes
2455 if (PmcgNodeCount > 0) {
2456 PmcgOffset = (UINT32)TableSize;
2457 // Size of PMCG node list.
2458 NodeSize = GetSizeofPmcgNodes (
2459 PmcgOffset,
2460 PmcgNodeList,
2461 PmcgNodeCount,
2462 &NodeIndexer
2463 );
2464 if (NodeSize > MAX_UINT32) {
2465 Status = EFI_INVALID_PARAMETER;
2466 DEBUG ((
2467 DEBUG_ERROR,
2468 "ERROR: IORT: Invalid Size of PMCG Nodes. Status = %r\n",
2469 Status
2470 ));
2471 goto error_handler;
2472 }
2473
2474 TableSize += NodeSize;
2475
2476 DEBUG ((
2477 DEBUG_INFO,
2478 " PmcgNodeCount = %d\n" \
2479 " PmcgOffset = %d\n",
2480 PmcgNodeCount,
2481 PmcgOffset
2482 ));
2483 }
2484
2485 // RMR Nodes
2486 if ((AcpiTableInfo->AcpiTableRevision >=
2487 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05) &&
2488 (RmrNodeCount > 0))
2489 {
2490 RmrOffset = (UINT32)TableSize;
2491 // Size of RMR node list.
2492 NodeSize = GetSizeofRmrNodes (
2493 RmrOffset,
2494 RmrNodeList,
2495 RmrNodeCount,
2496 &NodeIndexer
2497 );
2498 if (NodeSize > MAX_UINT32) {
2499 Status = EFI_INVALID_PARAMETER;
2500 DEBUG ((
2501 DEBUG_ERROR,
2502 "ERROR: IORT: Invalid Size of RMR Nodes. Status = %r\n",
2503 Status
2504 ));
2505 goto error_handler;
2506 }
2507
2508 TableSize += NodeSize;
2509
2510 DEBUG ((
2511 DEBUG_INFO,
2512 " RmrNodeCount = %d\n" \
2513 " RmrOffset = %d\n",
2514 RmrNodeCount,
2515 RmrOffset
2516 ));
2517 }
2518
2519 DEBUG ((
2520 DEBUG_INFO,
2521 "INFO: IORT:\n" \
2522 " IortNodeCount = %d\n" \
2523 " TableSize = 0x%lx\n",
2524 IortNodeCount,
2525 TableSize
2526 ));
2527
2528 if (TableSize > MAX_UINT32) {
2529 Status = EFI_INVALID_PARAMETER;
2530 DEBUG ((
2531 DEBUG_ERROR,
2532 "ERROR: IORT: IORT Table Size 0x%lx > MAX_UINT32," \
2533 " Status = %r\n",
2534 TableSize,
2535 Status
2536 ));
2537 goto error_handler;
2538 }
2539
2540 // Validate that the identifiers for the nodes are unique
2541 if (AcpiTableInfo->AcpiTableRevision >=
2542 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
2543 {
2544 Status = ValidateNodeIdentifiers (Generator->NodeIndexer, IortNodeCount);
2545 if (EFI_ERROR (Status)) {
2546 DEBUG ((
2547 DEBUG_ERROR,
2548 "ERROR: IORT: Node Identifier not unique. Status = %r\n",
2549 Status
2550 ));
2551 goto error_handler;
2552 }
2553 }
2554
2555 // Allocate the Buffer for IORT table
2556 *Table = (EFI_ACPI_DESCRIPTION_HEADER *)AllocateZeroPool (TableSize);
2557 if (*Table == NULL) {
2558 Status = EFI_OUT_OF_RESOURCES;
2559 DEBUG ((
2560 DEBUG_ERROR,
2561 "ERROR: IORT: Failed to allocate memory for IORT Table, Size = %d," \
2562 " Status = %r\n",
2563 TableSize,
2564 Status
2565 ));
2566 goto error_handler;
2567 }
2568
2569 Iort = (EFI_ACPI_6_0_IO_REMAPPING_TABLE *)*Table;
2570
2571 DEBUG ((
2572 DEBUG_INFO,
2573 "IORT: Iort = 0x%p TableSize = 0x%lx\n",
2574 Iort,
2575 TableSize
2576 ));
2577
2578 Status = AddAcpiHeader (
2579 CfgMgrProtocol,
2580 This,
2581 &Iort->Header,
2582 AcpiTableInfo,
2583 (UINT32)TableSize
2584 );
2585 if (EFI_ERROR (Status)) {
2586 DEBUG ((
2587 DEBUG_ERROR,
2588 "ERROR: IORT: Failed to add ACPI header. Status = %r\n",
2589 Status
2590 ));
2591 goto error_handler;
2592 }
2593
2594 // Update IORT table
2595 Iort->NumNodes = IortNodeCount;
2596 Iort->NodeOffset = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);
2597 Iort->Reserved = EFI_ACPI_RESERVED_DWORD;
2598
2599 if (ItsGroupNodeCount > 0) {
2600 Status = AddItsGroupNodes (
2601 This,
2602 CfgMgrProtocol,
2603 AcpiTableInfo,
2604 Iort,
2605 ItsGroupOffset,
2606 ItsGroupNodeList,
2607 ItsGroupNodeCount
2608 );
2609 if (EFI_ERROR (Status)) {
2610 DEBUG ((
2611 DEBUG_ERROR,
2612 "ERROR: IORT: Failed to add ITS Group Node. Status = %r\n",
2613 Status
2614 ));
2615 goto error_handler;
2616 }
2617 }
2618
2619 if (NamedComponentNodeCount > 0) {
2620 Status = AddNamedComponentNodes (
2621 This,
2622 CfgMgrProtocol,
2623 AcpiTableInfo,
2624 Iort,
2625 NamedComponentOffset,
2626 NamedComponentNodeList,
2627 NamedComponentNodeCount
2628 );
2629 if (EFI_ERROR (Status)) {
2630 DEBUG ((
2631 DEBUG_ERROR,
2632 "ERROR: IORT: Failed to add Named Component Node. Status = %r\n",
2633 Status
2634 ));
2635 goto error_handler;
2636 }
2637 }
2638
2639 if (RootComplexNodeCount > 0) {
2640 Status = AddRootComplexNodes (
2641 This,
2642 CfgMgrProtocol,
2643 AcpiTableInfo,
2644 Iort,
2645 RootComplexOffset,
2646 RootComplexNodeList,
2647 RootComplexNodeCount
2648 );
2649 if (EFI_ERROR (Status)) {
2650 DEBUG ((
2651 DEBUG_ERROR,
2652 "ERROR: IORT: Failed to add Root Complex Node. Status = %r\n",
2653 Status
2654 ));
2655 goto error_handler;
2656 }
2657 }
2658
2659 if (SmmuV1V2NodeCount > 0) {
2660 Status = AddSmmuV1V2Nodes (
2661 This,
2662 CfgMgrProtocol,
2663 AcpiTableInfo,
2664 Iort,
2665 SmmuV1V2Offset,
2666 SmmuV1V2NodeList,
2667 SmmuV1V2NodeCount
2668 );
2669 if (EFI_ERROR (Status)) {
2670 DEBUG ((
2671 DEBUG_ERROR,
2672 "ERROR: IORT: Failed to add SMMU v1/v2 Node. Status = %r\n",
2673 Status
2674 ));
2675 goto error_handler;
2676 }
2677 }
2678
2679 if (SmmuV3NodeCount > 0) {
2680 Status = AddSmmuV3Nodes (
2681 This,
2682 CfgMgrProtocol,
2683 AcpiTableInfo,
2684 Iort,
2685 SmmuV3Offset,
2686 SmmuV3NodeList,
2687 SmmuV3NodeCount
2688 );
2689 if (EFI_ERROR (Status)) {
2690 DEBUG ((
2691 DEBUG_ERROR,
2692 "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
2693 Status
2694 ));
2695 goto error_handler;
2696 }
2697 }
2698
2699 if (PmcgNodeCount > 0) {
2700 Status = AddPmcgNodes (
2701 This,
2702 CfgMgrProtocol,
2703 AcpiTableInfo,
2704 Iort,
2705 PmcgOffset,
2706 PmcgNodeList,
2707 PmcgNodeCount
2708 );
2709 if (EFI_ERROR (Status)) {
2710 DEBUG ((
2711 DEBUG_ERROR,
2712 "ERROR: IORT: Failed to add PMCG Node. Status = %r\n",
2713 Status
2714 ));
2715 goto error_handler;
2716 }
2717 }
2718
2719 if ((AcpiTableInfo->AcpiTableRevision >=
2720 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05) &&
2721 (RmrNodeCount > 0))
2722 {
2723 Status = AddRmrNodes (
2724 This,
2725 CfgMgrProtocol,
2726 AcpiTableInfo,
2727 Iort,
2728 RmrOffset,
2729 RmrNodeList,
2730 RmrNodeCount
2731 );
2732 if (EFI_ERROR (Status)) {
2733 DEBUG ((
2734 DEBUG_ERROR,
2735 "ERROR: IORT: Failed to add RMR Node. Status = %r\n",
2736 Status
2737 ));
2738 goto error_handler;
2739 }
2740 }
2741
2742 return EFI_SUCCESS;
2743
2744 error_handler:
2745 if (Generator->NodeIndexer != NULL) {
2746 FreePool (Generator->NodeIndexer);
2747 Generator->NodeIndexer = NULL;
2748 }
2749
2750 if (*Table != NULL) {
2751 FreePool (*Table);
2752 *Table = NULL;
2753 }
2754
2755 return Status;
2756 }
2757
2758 /** Free any resources allocated for constructing the IORT
2759
2760 @param [in] This Pointer to the table generator.
2761 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
2762 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
2763 Protocol Interface.
2764 @param [in, out] Table Pointer to the ACPI Table.
2765
2766 @retval EFI_SUCCESS The resources were freed successfully.
2767 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
2768 **/
2769 STATIC
2770 EFI_STATUS
2771 FreeIortTableResources (
2772 IN CONST ACPI_TABLE_GENERATOR *CONST This,
2773 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
2774 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
2775 IN OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table
2776 )
2777 {
2778 ACPI_IORT_GENERATOR *Generator;
2779
2780 ASSERT (This != NULL);
2781 ASSERT (AcpiTableInfo != NULL);
2782 ASSERT (CfgMgrProtocol != NULL);
2783 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
2784 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
2785
2786 Generator = (ACPI_IORT_GENERATOR *)This;
2787
2788 // Free any memory allocated by the generator
2789 if (Generator->NodeIndexer != NULL) {
2790 FreePool (Generator->NodeIndexer);
2791 Generator->NodeIndexer = NULL;
2792 }
2793
2794 if ((Table == NULL) || (*Table == NULL)) {
2795 DEBUG ((DEBUG_ERROR, "ERROR: IORT: Invalid Table Pointer\n"));
2796 ASSERT ((Table != NULL) && (*Table != NULL));
2797 return EFI_INVALID_PARAMETER;
2798 }
2799
2800 FreePool (*Table);
2801 *Table = NULL;
2802 return EFI_SUCCESS;
2803 }
2804
2805 /** The IORT Table Generator revision.
2806 */
2807 #define IORT_GENERATOR_REVISION CREATE_REVISION (1, 0)
2808
2809 /** The interface for the MADT Table Generator.
2810 */
2811 STATIC
2812 ACPI_IORT_GENERATOR IortGenerator = {
2813 // ACPI table generator header
2814 {
2815 // Generator ID
2816 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdIort),
2817 // Generator Description
2818 L"ACPI.STD.IORT.GENERATOR",
2819 // ACPI Table Signature
2820 EFI_ACPI_6_4_IO_REMAPPING_TABLE_SIGNATURE,
2821 // ACPI Table Revision supported by this Generator
2822 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05,
2823 // Minimum supported ACPI Table Revision
2824 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00,
2825 // Creator ID
2826 TABLE_GENERATOR_CREATOR_ID_ARM,
2827 // Creator Revision
2828 IORT_GENERATOR_REVISION,
2829 // Build Table function
2830 BuildIortTable,
2831 // Free Resource function
2832 FreeIortTableResources,
2833 // Extended build function not needed
2834 NULL,
2835 // Extended build function not implemented by the generator.
2836 // Hence extended free resource function is not required.
2837 NULL
2838 },
2839
2840 // IORT Generator private data
2841
2842 // Iort Node count
2843 0,
2844 // Pointer to Iort node indexer
2845 NULL
2846 };
2847
2848 /** Register the Generator with the ACPI Table Factory.
2849
2850 @param [in] ImageHandle The handle to the image.
2851 @param [in] SystemTable Pointer to the System Table.
2852
2853 @retval EFI_SUCCESS The Generator is registered.
2854 @retval EFI_INVALID_PARAMETER A parameter is invalid.
2855 @retval EFI_ALREADY_STARTED The Generator for the Table ID
2856 is already registered.
2857 **/
2858 EFI_STATUS
2859 EFIAPI
2860 AcpiIortLibConstructor (
2861 IN EFI_HANDLE ImageHandle,
2862 IN EFI_SYSTEM_TABLE *SystemTable
2863 )
2864 {
2865 EFI_STATUS Status;
2866
2867 Status = RegisterAcpiTableGenerator (&IortGenerator.Header);
2868 DEBUG ((DEBUG_INFO, "IORT: Register Generator. Status = %r\n", Status));
2869 ASSERT_EFI_ERROR (Status);
2870 return Status;
2871 }
2872
2873 /** Deregister the Generator from the ACPI Table Factory.
2874
2875 @param [in] ImageHandle The handle to the image.
2876 @param [in] SystemTable Pointer to the System Table.
2877
2878 @retval EFI_SUCCESS The Generator is deregistered.
2879 @retval EFI_INVALID_PARAMETER A parameter is invalid.
2880 @retval EFI_NOT_FOUND The Generator is not registered.
2881 **/
2882 EFI_STATUS
2883 EFIAPI
2884 AcpiIortLibDestructor (
2885 IN EFI_HANDLE ImageHandle,
2886 IN EFI_SYSTEM_TABLE *SystemTable
2887 )
2888 {
2889 EFI_STATUS Status;
2890
2891 Status = DeregisterAcpiTableGenerator (&IortGenerator.Header);
2892 DEBUG ((DEBUG_INFO, "Iort: Deregister Generator. Status = %r\n", Status));
2893 ASSERT_EFI_ERROR (Status);
2894 return Status;
2895 }