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