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