ShellPkg/UefiShellAcpiViewCommandLib: Fix ECC issues
[mirror_edk2.git] / ShellPkg / Library / UefiShellAcpiViewCommandLib / Parsers / Iort / IortParser.c
1 /** @file\r
2   IORT table parser\r
3 \r
4   Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.\r
5   This program and the accompanying materials\r
6   are licensed and made available under the terms and conditions of the BSD License\r
7   which accompanies this distribution.  The full text of the license may be found at\r
8   http://opensource.org/licenses/bsd-license.php\r
9 \r
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 \r
13   @par Reference(s):\r
14     - IO Remapping Table, Platform Design Document, Revision C, 15 May 2017\r
15 **/\r
16 \r
17 #include <IndustryStandard/IoRemappingTable.h>\r
18 #include <Library/PrintLib.h>\r
19 #include <Library/UefiLib.h>\r
20 #include "AcpiParser.h"\r
21 #include "AcpiTableParser.h"\r
22 \r
23 // Local variables\r
24 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;\r
25 \r
26 /**\r
27   The EIORT_NODE enum describes the IORT Node types.\r
28 **/\r
29 typedef enum IortNode {\r
30   EIORT_NODE_ITS_GROUP,        ///< ITS Group node\r
31   EIORT_NODE_NAMED_COMPONENT,  ///< Named Component node\r
32   EIORT_NODE_ROOT_COMPLEX,     ///< Root Complex node\r
33   EIORT_NODE_SMMUV1_V2,        ///< SMMU v1/v2 node\r
34   EIORT_NODE_SMMUV3,           ///< SMMU v3 node\r
35   EIORT_NODE_PMCG,             ///< PMC group node\r
36   EIORT_NODE_MAX\r
37 } EIORT_NODE;\r
38 \r
39 // Local Variables\r
40 STATIC CONST UINT32* IortNodeCount;\r
41 STATIC CONST UINT32* IortNodeOffset;\r
42 \r
43 STATIC CONST UINT8* IortNodeType;\r
44 STATIC CONST UINT16* IortNodeLength;\r
45 STATIC CONST UINT32* IortIdMappingCount;\r
46 STATIC CONST UINT32* IortIdMappingOffset;\r
47 \r
48 STATIC CONST UINT32* InterruptContextCount;\r
49 STATIC CONST UINT32* InterruptContextOffset;\r
50 STATIC CONST UINT32* PmuInterruptCount;\r
51 STATIC CONST UINT32* PmuInterruptOffset;\r
52 \r
53 STATIC CONST UINT32* ItsCount;\r
54 \r
55 /**\r
56   This function validates the ID Mapping array count for the ITS node.\r
57 \r
58   @param [in] Ptr     Pointer to the start of the field data.\r
59   @param [in] Context Pointer to context specific information e.g. this\r
60                       could be a pointer to the ACPI table header.\r
61 **/\r
62 STATIC\r
63 VOID\r
64 EFIAPI\r
65 ValidateItsIdMappingCount (\r
66   IN UINT8* Ptr,\r
67   IN VOID*  Context\r
68   );\r
69 \r
70 /**\r
71   This function validates the ID Mapping array offset for the ITS node.\r
72 \r
73   @param [in] Ptr     Pointer to the start of the field data.\r
74   @param [in] Context Pointer to context specific information e.g. this\r
75                       could be a pointer to the ACPI table header.\r
76 **/\r
77 STATIC\r
78 VOID\r
79 EFIAPI\r
80 ValidateItsIdArrayReference (\r
81   IN UINT8* Ptr,\r
82   IN VOID*  Context\r
83   );\r
84 \r
85 /**\r
86   Helper Macro for populating the IORT Node header in the ACPI_PARSER array.\r
87 \r
88   @param [out] ValidateIdMappingCount    Optional pointer to a function for\r
89                                          validating the ID Mapping count.\r
90   @param [out] ValidateIdArrayReference  Optional pointer to a function for\r
91                                          validating the ID Array reference.\r
92 **/\r
93 #define PARSE_IORT_NODE_HEADER(ValidateIdMappingCount,                   \\r
94                                ValidateIdArrayReference)                 \\r
95   { L"Type", 1, 0, L"%d", NULL, (VOID**)&IortNodeType, NULL, NULL },     \\r
96   { L"Length", 2, 1, L"%d", NULL, (VOID**)&IortNodeLength, NULL, NULL }, \\r
97   { L"Revision", 1, 3, L"%d", NULL, NULL, NULL, NULL },                  \\r
98   { L"Reserved", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },                \\r
99   { L"Number of ID mappings", 4, 8, L"%d", NULL,                         \\r
100     (VOID**)&IortIdMappingCount, ValidateIdMappingCount, NULL },         \\r
101   { L"Reference to ID Array", 4, 12, L"0x%x", NULL,                      \\r
102     (VOID**)&IortIdMappingOffset, ValidateIdArrayReference, NULL }\r
103 \r
104 /**\r
105   An ACPI_PARSER array describing the ACPI IORT Table\r
106 **/\r
107 STATIC CONST ACPI_PARSER IortParser[] = {\r
108   PARSE_ACPI_HEADER (&AcpiHdrInfo),\r
109   {L"Number of IORT Nodes", 4, 36, L"%d", NULL,\r
110    (VOID**)&IortNodeCount, NULL, NULL},\r
111   {L"Offset to Array of IORT Nodes", 4, 40, L"0x%x", NULL,\r
112    (VOID**)&IortNodeOffset, NULL, NULL},\r
113   {L"Reserved", 4, 44, L"0x%x", NULL, NULL, NULL, NULL}\r
114 };\r
115 \r
116 /**\r
117   An ACPI_PARSER array describing the IORT node header structure.\r
118 **/\r
119 STATIC CONST ACPI_PARSER IortNodeHeaderParser[] = {\r
120   PARSE_IORT_NODE_HEADER (NULL, NULL)\r
121 };\r
122 \r
123 /**\r
124   An ACPI_PARSER array describing the IORT SMMUv1/2 node.\r
125 **/\r
126 STATIC CONST ACPI_PARSER IortNodeSmmuV1V2Parser[] = {\r
127   PARSE_IORT_NODE_HEADER (NULL, NULL),\r
128   {L"Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL},\r
129   {L"Span", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL},\r
130   {L"Model", 4, 32, L"%d", NULL, NULL, NULL, NULL},\r
131   {L"Flags", 4, 36, L"0x%x", NULL, NULL, NULL, NULL},\r
132   {L"Reference to Global Interrupt Array", 4, 40, L"0x%x", NULL, NULL, NULL,\r
133    NULL},\r
134   {L"Number of context interrupts", 4, 44, L"%d", NULL,\r
135    (VOID**)&InterruptContextCount, NULL, NULL},\r
136   {L"Reference to Context Interrupt Array", 4, 48, L"0x%x", NULL,\r
137    (VOID**)&InterruptContextOffset, NULL, NULL},\r
138   {L"Number of PMU Interrupts", 4, 52, L"%d", NULL,\r
139    (VOID**)&PmuInterruptCount, NULL, NULL},\r
140   {L"Reference to PMU Interrupt Array", 4, 56, L"0x%x", NULL,\r
141    (VOID**)&PmuInterruptOffset, NULL, NULL},\r
142 \r
143   // Interrupt Array\r
144   {L"SMMU_NSgIrpt", 4, 60, L"0x%x", NULL, NULL, NULL, NULL},\r
145   {L"SMMU_NSgIrpt interrupt flags", 4, 64, L"0x%x", NULL, NULL, NULL, NULL},\r
146   {L"SMMU_NSgCfgIrpt", 4, 68, L"0x%x", NULL, NULL, NULL, NULL},\r
147   {L"SMMU_NSgCfgIrpt interrupt flags", 4, 72, L"0x%x", NULL, NULL, NULL, NULL}\r
148 };\r
149 \r
150 /**\r
151   An ACPI_PARSER array describing the SMMUv1/2 Node Interrupt Array.\r
152 **/\r
153 STATIC CONST ACPI_PARSER InterruptArrayParser[] = {\r
154   {L"  Interrupt GSIV", 4, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
155   {L"  Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}\r
156 };\r
157 \r
158 /**\r
159   An ACPI_PARSER array describing the IORT ID Mapping.\r
160 **/\r
161 STATIC CONST ACPI_PARSER IortNodeIdMappingParser[] = {\r
162   {L"  Input base", 4, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
163   {L"  Number of IDs", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
164   {L"  Output base", 4, 8, L"0x%x", NULL, NULL, NULL, NULL},\r
165   {L"  Output reference", 4, 12, L"0x%x", NULL, NULL, NULL, NULL},\r
166   {L"  Flags", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}\r
167 };\r
168 \r
169 /**\r
170   An ACPI_PARSER array describing the IORT SMMUv3 node.\r
171 **/\r
172 STATIC CONST ACPI_PARSER IortNodeSmmuV3Parser[] = {\r
173   PARSE_IORT_NODE_HEADER (NULL, NULL),\r
174   {L"Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL},\r
175   {L"Flags", 4, 24, L"0x%x", NULL, NULL, NULL, NULL},\r
176   {L"Reserved", 4, 28, L"0x%x", NULL, NULL, NULL, NULL},\r
177   {L"VATOS Address", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL},\r
178   {L"Model", 4, 40, L"%d", NULL, NULL, NULL, NULL},\r
179   {L"Event", 4, 44, L"0x%x", NULL, NULL, NULL, NULL},\r
180   {L"PRI", 4, 48, L"0x%x", NULL, NULL, NULL, NULL},\r
181   {L"GERR", 4, 52, L"0x%x", NULL, NULL, NULL, NULL},\r
182   {L"Sync", 4, 56, L"0x%x", NULL, NULL, NULL, NULL}\r
183 };\r
184 \r
185 /**\r
186   An ACPI_PARSER array describing the IORT ITS node.\r
187 **/\r
188 STATIC CONST ACPI_PARSER IortNodeItsParser[] = {\r
189   PARSE_IORT_NODE_HEADER (\r
190     ValidateItsIdMappingCount,\r
191     ValidateItsIdArrayReference\r
192     ),\r
193   {L"  Number of ITSs", 4, 16, L"%d", NULL, (VOID**)&ItsCount, NULL}\r
194 };\r
195 \r
196 /**\r
197   An ACPI_PARSER array describing the ITS ID.\r
198 **/\r
199 STATIC CONST ACPI_PARSER ItsIdParser[] = {\r
200   { L"  GIC ITS Identifier", 4, 0, L"%d", NULL, NULL, NULL }\r
201 };\r
202 \r
203 /**\r
204   An ACPI_PARSER array describing the IORT Names Component node.\r
205 **/\r
206 STATIC CONST ACPI_PARSER IortNodeNamedComponentParser[] = {\r
207   PARSE_IORT_NODE_HEADER (NULL, NULL),\r
208   {L"Node Flags", 4, 16, L"%d", NULL, NULL, NULL, NULL},\r
209   {L"Memory access properties", 8, 20, L"0x%lx", NULL, NULL, NULL, NULL},\r
210   {L"Device memory address size limit", 1, 28, L"%d", NULL, NULL, NULL, NULL}\r
211 };\r
212 \r
213 /**\r
214   An ACPI_PARSER array describing the IORT Root Complex node.\r
215 **/\r
216 STATIC CONST ACPI_PARSER IortNodeRootComplexParser[] = {\r
217   PARSE_IORT_NODE_HEADER (NULL, NULL),\r
218   {L"Memory access properties", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL},\r
219   {L"ATS Attribute", 4, 24, L"0x%x", NULL, NULL, NULL, NULL},\r
220   {L"PCI Segment number", 4, 28, L"0x%x", NULL, NULL, NULL, NULL}\r
221 };\r
222 \r
223 /**\r
224   An ACPI_PARSER array describing the IORT PMCG node.\r
225 **/\r
226 STATIC CONST ACPI_PARSER IortNodePmcgParser[] = {\r
227   PARSE_IORT_NODE_HEADER (NULL, NULL),\r
228   {L"Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL},\r
229   {L"Overflow interrupt GSIV", 4, 24, L"0x%x", NULL, NULL, NULL, NULL},\r
230   {L"Node reference", 4, 28, L"0x%x", NULL, NULL, NULL, NULL},\r
231 };\r
232 \r
233 /**\r
234   This function validates the ID Mapping array count for the ITS node.\r
235 \r
236   @param [in] Ptr     Pointer to the start of the field data.\r
237   @param [in] Context Pointer to context specific information e.g. this\r
238                       could be a pointer to the ACPI table header.\r
239 **/\r
240 STATIC\r
241 VOID\r
242 EFIAPI\r
243 ValidateItsIdMappingCount (\r
244   IN UINT8* Ptr,\r
245   IN VOID*     Context\r
246   )\r
247 {\r
248   if (*(UINT32*)Ptr != 0) {\r
249     IncrementErrorCount ();\r
250     Print (L"\nERROR: IORT ID Mapping count must be zero.");\r
251   }\r
252 }\r
253 \r
254 /**\r
255   This function validates the ID Mapping array offset for the ITS node.\r
256 \r
257   @param [in] Ptr     Pointer to the start of the field data.\r
258   @param [in] Context Pointer to context specific information e.g. this\r
259                       could be a pointer to the ACPI table header.\r
260 **/\r
261 STATIC\r
262 VOID\r
263 EFIAPI\r
264 ValidateItsIdArrayReference (\r
265   IN UINT8* Ptr,\r
266   IN VOID*  Context\r
267   )\r
268 {\r
269   if (*(UINT32*)Ptr != 0) {\r
270     IncrementErrorCount ();\r
271     Print (L"\nERROR: IORT ID Mapping offset must be zero.");\r
272   }\r
273 }\r
274 \r
275 /**\r
276   This function parses the IORT Node Id Mapping array.\r
277 \r
278   @param [in] Ptr            Pointer to the start of the IORT Table.\r
279   @param [in] MappingCount   The ID Mapping count.\r
280   @param [in] MappingOffset  The offset of the ID Mapping array\r
281                              from the start of the IORT table.\r
282 **/\r
283 STATIC\r
284 VOID\r
285 DumpIortNodeIdMappings (\r
286   IN UINT8* Ptr,\r
287   IN UINT32 MappingCount,\r
288   IN UINT32 MappingOffset\r
289   )\r
290 {\r
291   UINT8* IdMappingPtr;\r
292   UINT32 Index;\r
293   UINT32 Offset;\r
294   CHAR8  Buffer[40];  // Used for AsciiName param of ParseAcpi\r
295 \r
296   IdMappingPtr = Ptr + MappingOffset;\r
297   Index = 0;\r
298   while (Index < MappingCount) {\r
299     AsciiSPrint (\r
300       Buffer,\r
301       sizeof (Buffer),\r
302       "ID Mapping [%d]",\r
303       Index\r
304       );\r
305     Offset = ParseAcpi (\r
306                TRUE,\r
307                4,\r
308                Buffer,\r
309                IdMappingPtr,\r
310                20,\r
311                PARSER_PARAMS (IortNodeIdMappingParser)\r
312                );\r
313     IdMappingPtr += Offset;\r
314     Index++;\r
315   }\r
316 }\r
317 \r
318 /**\r
319   This function parses the IORT SMMUv1/2 node.\r
320 \r
321   @param [in] Ptr            Pointer to the start of the buffer.\r
322   @param [in] Length         Length of the buffer.\r
323   @param [in] MappingCount   The ID Mapping count.\r
324   @param [in] MappingOffset  The offset of the ID Mapping array\r
325                              from the start of the IORT table.\r
326 **/\r
327 STATIC\r
328 VOID\r
329 DumpIortNodeSmmuV1V2 (\r
330   IN UINT8* Ptr,\r
331   IN UINT16 Length,\r
332   IN UINT32 MappingCount,\r
333   IN UINT32 MappingOffset\r
334   )\r
335 {\r
336   UINT32 Index;\r
337   UINT32 Offset;\r
338   CHAR8  Buffer[50];  // Used for AsciiName param of ParseAcpi\r
339 \r
340   UINT8* ArrayPtr;\r
341 \r
342   ParseAcpi (\r
343     TRUE,\r
344     2,\r
345     "SMMUv1 or SMMUv2 Node",\r
346     Ptr,\r
347     Length,\r
348     PARSER_PARAMS (IortNodeSmmuV1V2Parser)\r
349     );\r
350 \r
351   ArrayPtr = Ptr + *InterruptContextOffset;\r
352   Index = 0;\r
353   while (Index < *InterruptContextCount) {\r
354     AsciiSPrint (\r
355       Buffer,\r
356       sizeof (Buffer),\r
357       "Context Interrupts Array [%d]",\r
358       Index\r
359       );\r
360     Offset = ParseAcpi (\r
361                TRUE,\r
362                4,\r
363                Buffer,\r
364                ArrayPtr,\r
365                8,\r
366                PARSER_PARAMS (InterruptArrayParser)\r
367                );\r
368     ArrayPtr += Offset;\r
369     Index++;\r
370   }\r
371 \r
372   ArrayPtr = Ptr + *PmuInterruptOffset;\r
373   Index = 0;\r
374   while (Index < *PmuInterruptCount) {\r
375     AsciiSPrint (\r
376       Buffer,\r
377       sizeof (Buffer),\r
378       "PMU Interrupts Array [%d]",\r
379       Index\r
380       );\r
381     Offset = ParseAcpi (\r
382                TRUE,\r
383                4,\r
384                Buffer,\r
385                ArrayPtr,\r
386                8,\r
387                PARSER_PARAMS (InterruptArrayParser)\r
388                );\r
389     ArrayPtr += Offset;\r
390     Index++;\r
391   }\r
392 \r
393   if (*IortIdMappingCount != 0) {\r
394     DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);\r
395   }\r
396 }\r
397 \r
398 /**\r
399   This function parses the IORT SMMUv3 node.\r
400 \r
401   @param [in] Ptr            Pointer to the start of the buffer.\r
402   @param [in] Length         Length of the buffer.\r
403   @param [in] MappingCount   The ID Mapping count.\r
404   @param [in] MappingOffset  The offset of the ID Mapping array\r
405                              from the start of the IORT table.\r
406 **/\r
407 STATIC\r
408 VOID\r
409 DumpIortNodeSmmuV3 (\r
410   IN UINT8* Ptr,\r
411   IN UINT16 Length,\r
412   IN UINT32 MappingCount,\r
413   IN UINT32 MappingOffset\r
414   )\r
415 {\r
416   ParseAcpi (\r
417     TRUE,\r
418     2,\r
419     "SMMUV3 Node",\r
420     Ptr,\r
421     Length,\r
422     PARSER_PARAMS (IortNodeSmmuV3Parser)\r
423     );\r
424 \r
425   if (*IortIdMappingCount != 0) {\r
426     DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);\r
427   }\r
428 }\r
429 \r
430 /**\r
431   This function parses the IORT ITS node.\r
432 \r
433   @param [in] Ptr            Pointer to the start of the buffer.\r
434   @param [in] Length         Length of the buffer.\r
435 **/\r
436 STATIC\r
437 VOID\r
438 DumpIortNodeIts (\r
439   IN UINT8* Ptr,\r
440   IN UINT16 Length\r
441   )\r
442 {\r
443   UINT32 Offset;\r
444   UINT32 Index;\r
445   UINT8* ItsIdPtr;\r
446   CHAR8  Buffer[80];  // Used for AsciiName param of ParseAcpi\r
447 \r
448   Offset = ParseAcpi (\r
449              TRUE,\r
450              2,\r
451              "ITS Node",\r
452              Ptr,\r
453              Length,\r
454              PARSER_PARAMS (IortNodeItsParser)\r
455              );\r
456 \r
457   ItsIdPtr = Ptr + Offset;\r
458   Index = 0;\r
459   while (Index < *ItsCount) {\r
460     AsciiSPrint (\r
461       Buffer,\r
462       sizeof (Buffer),\r
463       "GIC ITS Identifier Array [%d]",\r
464       Index\r
465       );\r
466     Offset = ParseAcpi (\r
467                TRUE,\r
468                4,\r
469                Buffer,\r
470                ItsIdPtr,\r
471                4,\r
472                PARSER_PARAMS (ItsIdParser)\r
473                );\r
474     ItsIdPtr += Offset;\r
475     Index++;\r
476   }\r
477 \r
478   // Note: ITS does not have the ID Mappings Array\r
479 }\r
480 \r
481 /**\r
482   This function parses the IORT Named Component node.\r
483 \r
484   @param [in] Ptr            Pointer to the start of the buffer.\r
485   @param [in] Length         Length of the buffer.\r
486   @param [in] MappingCount   The ID Mapping count.\r
487   @param [in] MappingOffset  The offset of the ID Mapping array\r
488                              from the start of the IORT table.\r
489 **/\r
490 STATIC\r
491 VOID\r
492 DumpIortNodeNamedComponent (\r
493   IN UINT8* Ptr,\r
494   IN UINT16 Length,\r
495   IN UINT32 MappingCount,\r
496   IN UINT32 MappingOffset\r
497   )\r
498 {\r
499   UINT32 Offset;\r
500   UINT32 Index;\r
501   UINT8* DeviceNamePtr;\r
502   UINT32 DeviceNameLength;\r
503 \r
504   Offset = ParseAcpi (\r
505              TRUE,\r
506              2,\r
507              "Named Component Node",\r
508              Ptr,\r
509              Length,\r
510              PARSER_PARAMS (IortNodeNamedComponentParser)\r
511              );\r
512 \r
513   DeviceNamePtr = Ptr + Offset;\r
514   // Estimate the Device Name length\r
515   DeviceNameLength = Length - Offset - (MappingCount * 20);\r
516   PrintFieldName (2, L"Device Object Name");\r
517   Index = 0;\r
518   while ((Index < DeviceNameLength) && (DeviceNamePtr[Index] != 0)) {\r
519     Print (L"%c", DeviceNamePtr[Index++]);\r
520   }\r
521   Print (L"\n");\r
522 \r
523   if (*IortIdMappingCount != 0) {\r
524     DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);\r
525   }\r
526 }\r
527 \r
528 /**\r
529   This function parses the IORT Root Complex node.\r
530 \r
531   @param [in] Ptr            Pointer to the start of the buffer.\r
532   @param [in] Length         Length of the buffer.\r
533   @param [in] MappingCount   The ID Mapping count.\r
534   @param [in] MappingOffset  The offset of the ID Mapping array\r
535                              from the start of the IORT table.\r
536 **/\r
537 STATIC\r
538 VOID\r
539 DumpIortNodeRootComplex (\r
540   IN UINT8* Ptr,\r
541   IN UINT16 Length,\r
542   IN UINT32 MappingCount,\r
543   IN UINT32 MappingOffset\r
544   )\r
545 {\r
546   ParseAcpi (\r
547     TRUE,\r
548     2,\r
549     "Root Complex Node",\r
550     Ptr,\r
551     Length,\r
552     PARSER_PARAMS (IortNodeRootComplexParser)\r
553     );\r
554 \r
555   if (*IortIdMappingCount != 0) {\r
556     DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);\r
557   }\r
558 }\r
559 \r
560 /**\r
561   This function parses the IORT PMCG node.\r
562 \r
563   @param [in] Ptr            Pointer to the start of the buffer.\r
564   @param [in] Length         Length of the buffer.\r
565   @param [in] MappingCount   The ID Mapping count.\r
566   @param [in] MappingOffset  The offset of the ID Mapping array\r
567                              from the start of the IORT table.\r
568 **/\r
569 STATIC\r
570 VOID\r
571 DumpIortNodePmcg (\r
572   IN UINT8* Ptr,\r
573   IN UINT16 Length,\r
574   IN UINT32 MappingCount,\r
575   IN UINT32 MappingOffset\r
576 )\r
577 {\r
578   ParseAcpi (\r
579     TRUE,\r
580     2,\r
581     "PMCG Node",\r
582     Ptr,\r
583     Length,\r
584     PARSER_PARAMS (IortNodePmcgParser)\r
585   );\r
586 \r
587   if (*IortIdMappingCount != 0) {\r
588     DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);\r
589   }\r
590 \r
591   if (*IortIdMappingCount > 1) {\r
592     IncrementErrorCount ();\r
593     Print (\r
594       L"ERROR: ID mapping must not be greater than 1. Id Mapping Count =%d\n",\r
595       *IortIdMappingCount\r
596       );\r
597   }\r
598 }\r
599 \r
600 /**\r
601   This function parses the ACPI IORT table.\r
602   When trace is enabled this function parses the IORT table and traces the ACPI fields.\r
603 \r
604   This function also parses the following nodes:\r
605     - ITS Group\r
606     - Named Component\r
607     - Root Complex\r
608     - SMMUv1/2\r
609     - SMMUv3\r
610     - PMCG\r
611 \r
612   This function also performs validation of the ACPI table fields.\r
613 \r
614   @param [in] Trace              If TRUE, trace the ACPI fields.\r
615   @param [in] Ptr                Pointer to the start of the buffer.\r
616   @param [in] AcpiTableLength    Length of the ACPI table.\r
617   @param [in] AcpiTableRevision  Revision of the ACPI table.\r
618 **/\r
619 VOID\r
620 EFIAPI\r
621 ParseAcpiIort (\r
622   IN BOOLEAN Trace,\r
623   IN UINT8*  Ptr,\r
624   IN UINT32  AcpiTableLength,\r
625   IN UINT8   AcpiTableRevision\r
626   )\r
627 {\r
628   UINT32 Offset;\r
629   UINT32 Index;\r
630   UINT8* NodePtr;\r
631 \r
632   if (!Trace) {\r
633     return;\r
634   }\r
635 \r
636   ParseAcpi (\r
637     TRUE,\r
638     0,\r
639     "IORT",\r
640     Ptr,\r
641     AcpiTableLength,\r
642     PARSER_PARAMS (IortParser)\r
643     );\r
644   Offset = *IortNodeOffset;\r
645   NodePtr = Ptr + Offset;\r
646   Index = 0;\r
647 \r
648   while ((Index < *IortNodeCount) && (Offset < AcpiTableLength)) {\r
649     // Parse the IORT Node Header\r
650     ParseAcpi (\r
651       FALSE,\r
652       0,\r
653       "IORT Node Header",\r
654       NodePtr,\r
655       16,\r
656       PARSER_PARAMS (IortNodeHeaderParser)\r
657       );\r
658     if (*IortNodeLength == 0) {\r
659       IncrementErrorCount ();\r
660       Print (L"ERROR: Parser error. Invalid table data.\n");\r
661       return;\r
662     }\r
663 \r
664     PrintFieldName (2, L"* Node Offset *");\r
665     Print (L"0x%x\n", Offset);\r
666 \r
667     switch (*IortNodeType) {\r
668       case EIORT_NODE_ITS_GROUP:\r
669         DumpIortNodeIts (\r
670           NodePtr,\r
671           *IortNodeLength\r
672           );\r
673         break;\r
674       case EIORT_NODE_NAMED_COMPONENT:\r
675         DumpIortNodeNamedComponent (\r
676           NodePtr,\r
677           *IortNodeLength,\r
678           *IortIdMappingCount,\r
679           *IortIdMappingOffset\r
680           );\r
681         break;\r
682       case EIORT_NODE_ROOT_COMPLEX:\r
683         DumpIortNodeRootComplex (\r
684           NodePtr,\r
685           *IortNodeLength,\r
686           *IortIdMappingCount,\r
687           *IortIdMappingOffset\r
688           );\r
689         break;\r
690       case EIORT_NODE_SMMUV1_V2:\r
691         DumpIortNodeSmmuV1V2 (\r
692           NodePtr,\r
693           *IortNodeLength,\r
694           *IortIdMappingCount,\r
695           *IortIdMappingOffset\r
696           );\r
697         break;\r
698       case EIORT_NODE_SMMUV3:\r
699         DumpIortNodeSmmuV3 (\r
700           NodePtr,\r
701           *IortNodeLength,\r
702           *IortIdMappingCount,\r
703           *IortIdMappingOffset\r
704           );\r
705         break;\r
706       case EIORT_NODE_PMCG:\r
707         DumpIortNodePmcg (\r
708           NodePtr,\r
709           *IortNodeLength,\r
710           *IortIdMappingCount,\r
711           *IortIdMappingOffset\r
712         );\r
713         break;\r
714 \r
715       default:\r
716         IncrementErrorCount ();\r
717         Print (L"ERROR: Unsupported IORT Node type = %d\n", *IortNodeType);\r
718     } // switch\r
719 \r
720     NodePtr += (*IortNodeLength);\r
721     Offset += (*IortNodeLength);\r
722   } // while\r
723 }\r