]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ShellPkg / Library / UefiShellAcpiViewCommandLib / Parsers / Iort / IortParser.c
CommitLineData
a6eaba4d 1/** @file\r
ee4dc24f
RN
2 IORT table parser\r
3\r
cd67efa1 4 Copyright (c) 2016 - 2022, Arm Limited. All rights reserved.\r
56ba3746 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
ee4dc24f
RN
6\r
7 @par Reference(s):\r
cd67efa1
SM
8 - IO Remapping Table, Platform Design Document, Revision E.d, Feb 2022\r
9 (https://developer.arm.com/documentation/den0049/)\r
8a210b9a
SM
10\r
11 @par Glossary:\r
12 - Ref - Reference\r
cd67efa1 13 - Desc - Descriptor\r
ee4dc24f
RN
14**/\r
15\r
16#include <IndustryStandard/IoRemappingTable.h>\r
17#include <Library/PrintLib.h>\r
18#include <Library/UefiLib.h>\r
19#include "AcpiParser.h"\r
20#include "AcpiTableParser.h"\r
e18ac66d 21#include "AcpiViewConfig.h"\r
ee4dc24f
RN
22\r
23// Local variables\r
47d20b54 24STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;\r
ee4dc24f 25\r
47d20b54
MK
26STATIC CONST UINT32 *IortNodeCount;\r
27STATIC CONST UINT32 *IortNodeOffset;\r
ee4dc24f 28\r
47d20b54
MK
29STATIC CONST UINT8 *IortNodeType;\r
30STATIC CONST UINT16 *IortNodeLength;\r
cd67efa1 31STATIC CONST UINT8 *IortNodeRevision;\r
47d20b54
MK
32STATIC CONST UINT32 *IortIdMappingCount;\r
33STATIC CONST UINT32 *IortIdMappingOffset;\r
ee4dc24f 34\r
47d20b54
MK
35STATIC CONST UINT32 *InterruptContextCount;\r
36STATIC CONST UINT32 *InterruptContextOffset;\r
37STATIC CONST UINT32 *PmuInterruptCount;\r
38STATIC CONST UINT32 *PmuInterruptOffset;\r
ee4dc24f 39\r
47d20b54 40STATIC CONST UINT32 *ItsCount;\r
ee4dc24f 41\r
cd67efa1
SM
42STATIC CONST UINT32 *RmrMemDescCount;\r
43STATIC CONST UINT32 *RmrMemDescOffset;\r
44\r
a6eaba4d
DB
45/**\r
46 This function validates the ID Mapping array count for the ITS node.\r
ee4dc24f
RN
47\r
48 @param [in] Ptr Pointer to the start of the field data.\r
49 @param [in] Context Pointer to context specific information e.g. this\r
50 could be a pointer to the ACPI table header.\r
a6eaba4d 51**/\r
ee4dc24f
RN
52STATIC\r
53VOID\r
54EFIAPI\r
55ValidateItsIdMappingCount (\r
47d20b54
MK
56 IN UINT8 *Ptr,\r
57 IN VOID *Context\r
795e706f
KK
58 )\r
59{\r
47d20b54 60 if (*(UINT32 *)Ptr != 0) {\r
795e706f
KK
61 IncrementErrorCount ();\r
62 Print (L"\nERROR: IORT ID Mapping count must be zero.");\r
63 }\r
64}\r
ee4dc24f 65\r
05f8e85f
KK
66/**\r
67 This function validates the ID Mapping array count for the Performance\r
68 Monitoring Counter Group (PMCG) 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
74STATIC\r
75VOID\r
76EFIAPI\r
77ValidatePmcgIdMappingCount (\r
47d20b54
MK
78 IN UINT8 *Ptr,\r
79 IN VOID *Context\r
05f8e85f
KK
80 )\r
81{\r
47d20b54 82 if (*(UINT32 *)Ptr > 1) {\r
05f8e85f
KK
83 IncrementErrorCount ();\r
84 Print (L"\nERROR: IORT ID Mapping count must not be greater than 1.");\r
85 }\r
86}\r
87\r
a6eaba4d
DB
88/**\r
89 This function validates the ID Mapping array offset for the ITS node.\r
ee4dc24f
RN
90\r
91 @param [in] Ptr Pointer to the start of the field data.\r
92 @param [in] Context Pointer to context specific information e.g. this\r
93 could be a pointer to the ACPI table header.\r
a6eaba4d 94**/\r
ee4dc24f
RN
95STATIC\r
96VOID\r
97EFIAPI\r
98ValidateItsIdArrayReference (\r
47d20b54
MK
99 IN UINT8 *Ptr,\r
100 IN VOID *Context\r
795e706f
KK
101 )\r
102{\r
47d20b54 103 if (*(UINT32 *)Ptr != 0) {\r
795e706f
KK
104 IncrementErrorCount ();\r
105 Print (L"\nERROR: IORT ID Mapping offset must be zero.");\r
106 }\r
107}\r
ee4dc24f 108\r
cd67efa1
SM
109/**\r
110 This function validates that the Physical Range address or length is not zero\r
111 and is 64K aligned.\r
112\r
113 @param [in] Ptr Pointer to the start of the field data.\r
114 @param [in] Context Pointer to context specific information e.g. this\r
115 could be a pointer to the ACPI table header.\r
116**/\r
117STATIC\r
118VOID\r
119EFIAPI\r
120ValidatePhysicalRange (\r
121 IN UINT8 *Ptr,\r
122 IN VOID *Context\r
123 )\r
124{\r
125 UINT64 Value;\r
126\r
127 Value = *(UINT64 *)Ptr;\r
128 if ((Value == 0) || ((Value & (SIZE_64KB - 1)) != 0)) {\r
129 IncrementErrorCount ();\r
130 Print (L"\nERROR: Physical Range must be 64K aligned and cannot be zero.");\r
131 }\r
132}\r
133\r
134/**\r
135 This function validates that the RMR memory range descriptor count.\r
136\r
137 @param [in] Ptr Pointer to the start of the field data.\r
138 @param [in] Context Pointer to context specific information e.g. this\r
139 could be a pointer to the ACPI table header.\r
140**/\r
141STATIC\r
142VOID\r
143EFIAPI\r
144ValidateRmrMemDescCount (\r
145 IN UINT8 *Ptr,\r
146 IN VOID *Context\r
147 )\r
148{\r
149 if (*(UINT32 *)Ptr == 0) {\r
150 IncrementErrorCount ();\r
151 Print (L"\nERROR: Memory Range Descriptor count must be >=1.");\r
152 }\r
153}\r
154\r
a6eaba4d
DB
155/**\r
156 Helper Macro for populating the IORT Node header in the ACPI_PARSER array.\r
ee4dc24f
RN
157\r
158 @param [out] ValidateIdMappingCount Optional pointer to a function for\r
159 validating the ID Mapping count.\r
160 @param [out] ValidateIdArrayReference Optional pointer to a function for\r
161 validating the ID Array reference.\r
a6eaba4d 162**/\r
cd67efa1
SM
163#define PARSE_IORT_NODE_HEADER(ValidateIdMappingCount, \\r
164 ValidateIdArrayReference) \\r
165 { L"Type", 1, 0, L"%d", NULL, (VOID**)&IortNodeType, NULL, NULL }, \\r
166 { L"Length", 2, 1, L"%d", NULL, (VOID**)&IortNodeLength, NULL, NULL }, \\r
167 { L"Revision", 1, 3, L"%d", NULL, (VOID**)&IortNodeRevision, NULL, NULL }, \\r
168 { L"Identifier", 4, 4, L"0x%x", NULL, NULL, NULL, NULL }, \\r
169 { L"Number of ID mappings", 4, 8, L"%d", NULL, \\r
170 (VOID**)&IortIdMappingCount, ValidateIdMappingCount, NULL }, \\r
171 { L"Reference to ID Array", 4, 12, L"0x%x", NULL, \\r
ee4dc24f
RN
172 (VOID**)&IortIdMappingOffset, ValidateIdArrayReference, NULL }\r
173\r
a6eaba4d
DB
174/**\r
175 An ACPI_PARSER array describing the ACPI IORT Table\r
176**/\r
47d20b54 177STATIC CONST ACPI_PARSER IortParser[] = {\r
ee4dc24f 178 PARSE_ACPI_HEADER (&AcpiHdrInfo),\r
47d20b54
MK
179 { L"Number of IORT Nodes", 4, 36, L"%d", NULL,\r
180 (VOID **)&IortNodeCount, NULL, NULL },\r
181 { L"Offset to Array of IORT Nodes",4, 40, L"0x%x", NULL,\r
182 (VOID **)&IortNodeOffset, NULL, NULL },\r
183 { L"Reserved", 4, 44, L"0x%x", NULL,NULL,NULL, NULL }\r
ee4dc24f
RN
184};\r
185\r
a6eaba4d
DB
186/**\r
187 An ACPI_PARSER array describing the IORT node header structure.\r
188**/\r
47d20b54 189STATIC CONST ACPI_PARSER IortNodeHeaderParser[] = {\r
ee4dc24f
RN
190 PARSE_IORT_NODE_HEADER (NULL, NULL)\r
191};\r
192\r
a6eaba4d
DB
193/**\r
194 An ACPI_PARSER array describing the IORT SMMUv1/2 node.\r
195**/\r
47d20b54
MK
196STATIC CONST ACPI_PARSER IortNodeSmmuV1V2Parser[] = {\r
197 PARSE_IORT_NODE_HEADER (NULL, NULL),\r
198 { L"Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL },\r
199 { L"Span", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL },\r
200 { L"Model", 4, 32, L"%d", NULL, NULL, NULL, NULL },\r
201 { L"Flags", 4, 36, L"0x%x", NULL, NULL, NULL, NULL },\r
8a210b9a 202 { L"Global Interrupt Array Ref", 4, 40, L"0x%x", NULL, NULL, NULL,\r
47d20b54
MK
203 NULL },\r
204 { L"Number of context interrupts", 4, 44, L"%d", NULL,\r
205 (VOID **)&InterruptContextCount, NULL, NULL },\r
8a210b9a 206 { L"Context Interrupt Array Ref", 4, 48, L"0x%x", NULL,\r
47d20b54
MK
207 (VOID **)&InterruptContextOffset, NULL, NULL },\r
208 { L"Number of PMU Interrupts", 4, 52, L"%d", NULL,\r
209 (VOID **)&PmuInterruptCount, NULL, NULL },\r
8a210b9a 210 { L"PMU Interrupt Array Ref", 4, 56, L"0x%x", NULL,\r
47d20b54 211 (VOID **)&PmuInterruptOffset, NULL, NULL },\r
ee4dc24f
RN
212\r
213 // Interrupt Array\r
47d20b54
MK
214 { L"SMMU_NSgIrpt", 4, 60, L"0x%x", NULL, NULL, NULL, NULL },\r
215 { L"SMMU_NSgIrpt interrupt flags", 4, 64, L"0x%x", NULL, NULL, NULL, NULL },\r
216 { L"SMMU_NSgCfgIrpt", 4, 68, L"0x%x", NULL, NULL, NULL, NULL },\r
217 { L"SMMU_NSgCfgIrpt interrupt flags",4, 72, L"0x%x", NULL, NULL, NULL, NULL }\r
ee4dc24f
RN
218};\r
219\r
a6eaba4d
DB
220/**\r
221 An ACPI_PARSER array describing the SMMUv1/2 Node Interrupt Array.\r
222**/\r
47d20b54
MK
223STATIC CONST ACPI_PARSER InterruptArrayParser[] = {\r
224 { L"Interrupt GSIV", 4, 0, L"0x%x", NULL, NULL, NULL, NULL },\r
225 { L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL }\r
ee4dc24f
RN
226};\r
227\r
a6eaba4d
DB
228/**\r
229 An ACPI_PARSER array describing the IORT ID Mapping.\r
230**/\r
47d20b54
MK
231STATIC CONST ACPI_PARSER IortNodeIdMappingParser[] = {\r
232 { L"Input base", 4, 0, L"0x%x", NULL, NULL, NULL, NULL },\r
233 { L"Number of IDs", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },\r
234 { L"Output base", 4, 8, L"0x%x", NULL, NULL, NULL, NULL },\r
235 { L"Output reference", 4, 12, L"0x%x", NULL, NULL, NULL, NULL },\r
236 { L"Flags", 4, 16, L"0x%x", NULL, NULL, NULL, NULL }\r
ee4dc24f
RN
237};\r
238\r
a6eaba4d
DB
239/**\r
240 An ACPI_PARSER array describing the IORT SMMUv3 node.\r
241**/\r
47d20b54 242STATIC CONST ACPI_PARSER IortNodeSmmuV3Parser[] = {\r
ee4dc24f 243 PARSE_IORT_NODE_HEADER (NULL, NULL),\r
47d20b54
MK
244 { L"Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL },\r
245 { L"Flags", 4, 24, L"0x%x", NULL, NULL, NULL, NULL },\r
246 { L"Reserved", 4, 28, L"0x%x", NULL, NULL, NULL, NULL },\r
247 { L"VATOS Address", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL },\r
248 { L"Model", 4, 40, L"%d", NULL, NULL, NULL, NULL },\r
249 { L"Event", 4, 44, L"0x%x", NULL, NULL, NULL, NULL },\r
250 { L"PRI", 4, 48, L"0x%x", NULL, NULL, NULL, NULL },\r
251 { L"GERR", 4, 52, L"0x%x", NULL, NULL, NULL, NULL },\r
252 { L"Sync", 4, 56, L"0x%x", NULL, NULL, NULL, NULL },\r
253 { L"Proximity domain", 4, 60, L"0x%x", NULL, NULL, NULL, NULL },\r
254 { L"Device ID mapping index", 4, 64, L"%d", NULL, NULL, NULL, NULL }\r
ee4dc24f
RN
255};\r
256\r
a6eaba4d
DB
257/**\r
258 An ACPI_PARSER array describing the IORT ITS node.\r
259**/\r
47d20b54 260STATIC CONST ACPI_PARSER IortNodeItsParser[] = {\r
ee4dc24f
RN
261 PARSE_IORT_NODE_HEADER (\r
262 ValidateItsIdMappingCount,\r
263 ValidateItsIdArrayReference\r
264 ),\r
47d20b54 265 { L"Number of ITSs", 4,16, L"%d", NULL, (VOID **)&ItsCount, NULL }\r
ee4dc24f
RN
266};\r
267\r
a6eaba4d
DB
268/**\r
269 An ACPI_PARSER array describing the ITS ID.\r
270**/\r
47d20b54 271STATIC CONST ACPI_PARSER ItsIdParser[] = {\r
5ed3b562 272 { L"GIC ITS Identifier", 4, 0, L"%d", NULL, NULL, NULL }\r
ee4dc24f
RN
273};\r
274\r
a6eaba4d
DB
275/**\r
276 An ACPI_PARSER array describing the IORT Names Component node.\r
277**/\r
47d20b54 278STATIC CONST ACPI_PARSER IortNodeNamedComponentParser[] = {\r
ee4dc24f 279 PARSE_IORT_NODE_HEADER (NULL, NULL),\r
47d20b54
MK
280 { L"Node Flags", 4, 16, L"%d", NULL, NULL, NULL, NULL },\r
281 { L"Memory access properties",8, 20, L"0x%lx", NULL, NULL, NULL, NULL },\r
282 { L"Device memory address size limit",1, 28, L"%d", NULL, NULL, NULL, NULL }\r
ee4dc24f
RN
283};\r
284\r
a6eaba4d
DB
285/**\r
286 An ACPI_PARSER array describing the IORT Root Complex node.\r
287**/\r
47d20b54 288STATIC CONST ACPI_PARSER IortNodeRootComplexParser[] = {\r
ee4dc24f 289 PARSE_IORT_NODE_HEADER (NULL, NULL),\r
cd67efa1
SM
290 { L"Memory access properties",8, 16, L"0x%lx", NULL, NULL, NULL, NULL },\r
291 { L"ATS Attribute", 4, 24, L"0x%x", NULL, NULL, NULL, NULL },\r
292 { L"PCI Segment number", 4, 28, L"0x%x", NULL, NULL, NULL, NULL },\r
293 { L"Memory access size limit",1, 32, L"0x%x", NULL, NULL, NULL, NULL },\r
294 { L"PASID capabilities", 2, 33, L"0x%x", NULL, NULL, NULL, NULL },\r
295 { L"Reserved", 1, 35, L"%x", NULL, NULL, NULL, NULL },\r
296 { L"Flags", 4, 36, L"0x%x", NULL, NULL, NULL, NULL },\r
ee4dc24f
RN
297};\r
298\r
a6eaba4d
DB
299/**\r
300 An ACPI_PARSER array describing the IORT PMCG node.\r
301**/\r
47d20b54 302STATIC CONST ACPI_PARSER IortNodePmcgParser[] = {\r
05f8e85f 303 PARSE_IORT_NODE_HEADER (ValidatePmcgIdMappingCount, NULL),\r
47d20b54
MK
304 { L"Page 0 Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL },\r
305 { L"Overflow interrupt GSIV", 4, 24, L"0x%x", NULL, NULL, NULL, NULL },\r
306 { L"Node reference", 4, 28, L"0x%x", NULL, NULL, NULL, NULL },\r
307 { L"Page 1 Base Address", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL }\r
ee4dc24f
RN
308};\r
309\r
cd67efa1
SM
310/**\r
311 An ACPI_PARSER array describing the IORT RMR node.\r
312**/\r
313STATIC CONST ACPI_PARSER IortNodeRmrParser[] = {\r
314 PARSE_IORT_NODE_HEADER (NULL, NULL),\r
315 { L"Flags", 4, 16, L"0x%x", NULL, NULL, NULL, NULL },\r
316 { L"Memory Range Desc count", 4, 20, L"%d", NULL,\r
317 (VOID **)&RmrMemDescCount, ValidateRmrMemDescCount,NULL },\r
318 { L"Memory Range Desc Ref", 4, 24, L"0x%x", NULL,\r
319 (VOID **)&RmrMemDescOffset, NULL, NULL }\r
320};\r
321\r
322/**\r
323 An ACPI_PARSER array describing the IORT RMR Memory Range Descriptor.\r
324**/\r
325STATIC CONST ACPI_PARSER IortNodeRmrMemRangeDescParser[] = {\r
326 { L"Physical Range offset", 8, 0, L"0x%lx", NULL, NULL, ValidatePhysicalRange,\r
327 NULL },\r
328 { L"Physical Range length", 8, 8, L"0x%lx", NULL, NULL, ValidatePhysicalRange,\r
329 NULL },\r
330 { L"Reserved", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}\r
331};\r
332\r
a6eaba4d
DB
333/**\r
334 This function parses the IORT Node Id Mapping array.\r
ee4dc24f 335\r
62cefaf4
KK
336 @param [in] Ptr Pointer to the start of the ID mapping array.\r
337 @param [in] Length Length of the buffer.\r
ee4dc24f 338 @param [in] MappingCount The ID Mapping count.\r
a6eaba4d 339**/\r
ee4dc24f
RN
340STATIC\r
341VOID\r
342DumpIortNodeIdMappings (\r
47d20b54
MK
343 IN UINT8 *Ptr,\r
344 IN UINT32 Length,\r
345 IN UINT32 MappingCount\r
ee4dc24f
RN
346 )\r
347{\r
47d20b54
MK
348 UINT32 Index;\r
349 UINT32 Offset;\r
350 CHAR8 Buffer[40]; // Used for AsciiName param of ParseAcpi\r
ee4dc24f 351\r
47d20b54 352 Index = 0;\r
62cefaf4
KK
353 Offset = 0;\r
354\r
355 while ((Index < MappingCount) &&\r
47d20b54
MK
356 (Offset < Length))\r
357 {\r
ee4dc24f
RN
358 AsciiSPrint (\r
359 Buffer,\r
360 sizeof (Buffer),\r
361 "ID Mapping [%d]",\r
362 Index\r
363 );\r
62cefaf4
KK
364 Offset += ParseAcpi (\r
365 TRUE,\r
366 4,\r
367 Buffer,\r
368 Ptr + Offset,\r
369 Length - Offset,\r
370 PARSER_PARAMS (IortNodeIdMappingParser)\r
371 );\r
ee4dc24f
RN
372 Index++;\r
373 }\r
374}\r
375\r
a6eaba4d
DB
376/**\r
377 This function parses the IORT SMMUv1/2 node.\r
ee4dc24f
RN
378\r
379 @param [in] Ptr Pointer to the start of the buffer.\r
380 @param [in] Length Length of the buffer.\r
381 @param [in] MappingCount The ID Mapping count.\r
382 @param [in] MappingOffset The offset of the ID Mapping array\r
383 from the start of the IORT table.\r
a6eaba4d 384**/\r
ee4dc24f
RN
385STATIC\r
386VOID\r
387DumpIortNodeSmmuV1V2 (\r
47d20b54
MK
388 IN UINT8 *Ptr,\r
389 IN UINT16 Length,\r
390 IN UINT32 MappingCount,\r
391 IN UINT32 MappingOffset\r
ee4dc24f
RN
392 )\r
393{\r
47d20b54
MK
394 UINT32 Index;\r
395 UINT32 Offset;\r
396 CHAR8 Buffer[50]; // Used for AsciiName param of ParseAcpi\r
ee4dc24f 397\r
ee4dc24f
RN
398 ParseAcpi (\r
399 TRUE,\r
400 2,\r
401 "SMMUv1 or SMMUv2 Node",\r
402 Ptr,\r
403 Length,\r
404 PARSER_PARAMS (IortNodeSmmuV1V2Parser)\r
405 );\r
406\r
ea26838a
KK
407 // Check if the values used to control the parsing logic have been\r
408 // successfully read.\r
409 if ((InterruptContextCount == NULL) ||\r
410 (InterruptContextOffset == NULL) ||\r
411 (PmuInterruptCount == NULL) ||\r
47d20b54
MK
412 (PmuInterruptOffset == NULL))\r
413 {\r
ea26838a
KK
414 IncrementErrorCount ();\r
415 Print (\r
416 L"ERROR: Insufficient SMMUv1/2 node length. Length = %d\n",\r
417 Length\r
418 );\r
419 return;\r
420 }\r
421\r
62cefaf4 422 Offset = *InterruptContextOffset;\r
47d20b54 423 Index = 0;\r
62cefaf4
KK
424\r
425 while ((Index < *InterruptContextCount) &&\r
47d20b54
MK
426 (Offset < Length))\r
427 {\r
ee4dc24f
RN
428 AsciiSPrint (\r
429 Buffer,\r
430 sizeof (Buffer),\r
431 "Context Interrupts Array [%d]",\r
432 Index\r
433 );\r
62cefaf4
KK
434 Offset += ParseAcpi (\r
435 TRUE,\r
436 4,\r
437 Buffer,\r
438 Ptr + Offset,\r
439 Length - Offset,\r
440 PARSER_PARAMS (InterruptArrayParser)\r
441 );\r
ee4dc24f
RN
442 Index++;\r
443 }\r
444\r
62cefaf4 445 Offset = *PmuInterruptOffset;\r
47d20b54 446 Index = 0;\r
62cefaf4
KK
447\r
448 while ((Index < *PmuInterruptCount) &&\r
47d20b54
MK
449 (Offset < Length))\r
450 {\r
ee4dc24f
RN
451 AsciiSPrint (\r
452 Buffer,\r
453 sizeof (Buffer),\r
454 "PMU Interrupts Array [%d]",\r
455 Index\r
456 );\r
62cefaf4
KK
457 Offset += ParseAcpi (\r
458 TRUE,\r
459 4,\r
460 Buffer,\r
461 Ptr + Offset,\r
462 Length - Offset,\r
463 PARSER_PARAMS (InterruptArrayParser)\r
464 );\r
ee4dc24f
RN
465 Index++;\r
466 }\r
467\r
62cefaf4
KK
468 DumpIortNodeIdMappings (\r
469 Ptr + MappingOffset,\r
470 Length - MappingOffset,\r
471 MappingCount\r
472 );\r
ee4dc24f
RN
473}\r
474\r
a6eaba4d
DB
475/**\r
476 This function parses the IORT SMMUv3 node.\r
ee4dc24f
RN
477\r
478 @param [in] Ptr Pointer to the start of the buffer.\r
479 @param [in] Length Length of the buffer.\r
480 @param [in] MappingCount The ID Mapping count.\r
481 @param [in] MappingOffset The offset of the ID Mapping array\r
482 from the start of the IORT table.\r
a6eaba4d 483**/\r
ee4dc24f
RN
484STATIC\r
485VOID\r
486DumpIortNodeSmmuV3 (\r
47d20b54
MK
487 IN UINT8 *Ptr,\r
488 IN UINT16 Length,\r
489 IN UINT32 MappingCount,\r
490 IN UINT32 MappingOffset\r
ee4dc24f
RN
491 )\r
492{\r
493 ParseAcpi (\r
494 TRUE,\r
495 2,\r
496 "SMMUV3 Node",\r
497 Ptr,\r
498 Length,\r
499 PARSER_PARAMS (IortNodeSmmuV3Parser)\r
500 );\r
501\r
62cefaf4
KK
502 DumpIortNodeIdMappings (\r
503 Ptr + MappingOffset,\r
504 Length - MappingOffset,\r
505 MappingCount\r
506 );\r
ee4dc24f
RN
507}\r
508\r
a6eaba4d
DB
509/**\r
510 This function parses the IORT ITS node.\r
ee4dc24f
RN
511\r
512 @param [in] Ptr Pointer to the start of the buffer.\r
513 @param [in] Length Length of the buffer.\r
a6eaba4d 514**/\r
ee4dc24f
RN
515STATIC\r
516VOID\r
517DumpIortNodeIts (\r
47d20b54
MK
518 IN UINT8 *Ptr,\r
519 IN UINT16 Length\r
ee4dc24f
RN
520 )\r
521{\r
47d20b54
MK
522 UINT32 Offset;\r
523 UINT32 Index;\r
524 CHAR8 Buffer[80]; // Used for AsciiName param of ParseAcpi\r
ee4dc24f
RN
525\r
526 Offset = ParseAcpi (\r
47d20b54
MK
527 TRUE,\r
528 2,\r
529 "ITS Node",\r
530 Ptr,\r
531 Length,\r
532 PARSER_PARAMS (IortNodeItsParser)\r
533 );\r
ee4dc24f 534\r
ea26838a
KK
535 // Check if the values used to control the parsing logic have been\r
536 // successfully read.\r
537 if (ItsCount == NULL) {\r
538 IncrementErrorCount ();\r
539 Print (\r
540 L"ERROR: Insufficient ITS group length. Length = %d.\n",\r
541 Length\r
542 );\r
543 return;\r
544 }\r
545\r
ee4dc24f 546 Index = 0;\r
62cefaf4
KK
547\r
548 while ((Index < *ItsCount) &&\r
47d20b54
MK
549 (Offset < Length))\r
550 {\r
ee4dc24f
RN
551 AsciiSPrint (\r
552 Buffer,\r
553 sizeof (Buffer),\r
554 "GIC ITS Identifier Array [%d]",\r
555 Index\r
556 );\r
62cefaf4
KK
557 Offset += ParseAcpi (\r
558 TRUE,\r
559 4,\r
560 Buffer,\r
561 Ptr + Offset,\r
562 Length - Offset,\r
563 PARSER_PARAMS (ItsIdParser)\r
564 );\r
ee4dc24f
RN
565 Index++;\r
566 }\r
567\r
568 // Note: ITS does not have the ID Mappings Array\r
569}\r
570\r
a6eaba4d
DB
571/**\r
572 This function parses the IORT Named Component node.\r
ee4dc24f
RN
573\r
574 @param [in] Ptr Pointer to the start of the buffer.\r
575 @param [in] Length Length of the buffer.\r
576 @param [in] MappingCount The ID Mapping count.\r
577 @param [in] MappingOffset The offset of the ID Mapping array\r
578 from the start of the IORT table.\r
a6eaba4d 579**/\r
ee4dc24f
RN
580STATIC\r
581VOID\r
582DumpIortNodeNamedComponent (\r
47d20b54
MK
583 IN UINT8 *Ptr,\r
584 IN UINT16 Length,\r
585 IN UINT32 MappingCount,\r
586 IN UINT32 MappingOffset\r
ee4dc24f
RN
587 )\r
588{\r
47d20b54 589 UINT32 Offset;\r
ee4dc24f
RN
590\r
591 Offset = ParseAcpi (\r
592 TRUE,\r
593 2,\r
594 "Named Component Node",\r
595 Ptr,\r
596 Length,\r
597 PARSER_PARAMS (IortNodeNamedComponentParser)\r
598 );\r
599\r
ee4dc24f 600 // Estimate the Device Name length\r
ee4dc24f 601 PrintFieldName (2, L"Device Object Name");\r
62cefaf4
KK
602\r
603 while ((*(Ptr + Offset) != 0) &&\r
47d20b54
MK
604 (Offset < Length))\r
605 {\r
62cefaf4
KK
606 Print (L"%c", *(Ptr + Offset));\r
607 Offset++;\r
ee4dc24f 608 }\r
47d20b54 609\r
ee4dc24f
RN
610 Print (L"\n");\r
611\r
62cefaf4
KK
612 DumpIortNodeIdMappings (\r
613 Ptr + MappingOffset,\r
614 Length - MappingOffset,\r
615 MappingCount\r
616 );\r
ee4dc24f
RN
617}\r
618\r
a6eaba4d
DB
619/**\r
620 This function parses the IORT Root Complex node.\r
ee4dc24f
RN
621\r
622 @param [in] Ptr Pointer to the start of the buffer.\r
623 @param [in] Length Length of the buffer.\r
624 @param [in] MappingCount The ID Mapping count.\r
625 @param [in] MappingOffset The offset of the ID Mapping array\r
626 from the start of the IORT table.\r
a6eaba4d 627**/\r
ee4dc24f
RN
628STATIC\r
629VOID\r
630DumpIortNodeRootComplex (\r
47d20b54
MK
631 IN UINT8 *Ptr,\r
632 IN UINT16 Length,\r
633 IN UINT32 MappingCount,\r
634 IN UINT32 MappingOffset\r
ee4dc24f
RN
635 )\r
636{\r
637 ParseAcpi (\r
638 TRUE,\r
639 2,\r
640 "Root Complex Node",\r
641 Ptr,\r
642 Length,\r
643 PARSER_PARAMS (IortNodeRootComplexParser)\r
644 );\r
645\r
62cefaf4
KK
646 DumpIortNodeIdMappings (\r
647 Ptr + MappingOffset,\r
648 Length - MappingOffset,\r
649 MappingCount\r
650 );\r
ee4dc24f
RN
651}\r
652\r
a6eaba4d
DB
653/**\r
654 This function parses the IORT PMCG node.\r
ee4dc24f
RN
655\r
656 @param [in] Ptr Pointer to the start of the buffer.\r
657 @param [in] Length Length of the buffer.\r
658 @param [in] MappingCount The ID Mapping count.\r
659 @param [in] MappingOffset The offset of the ID Mapping array\r
660 from the start of the IORT table.\r
a6eaba4d 661**/\r
ee4dc24f
RN
662STATIC\r
663VOID\r
664DumpIortNodePmcg (\r
47d20b54
MK
665 IN UINT8 *Ptr,\r
666 IN UINT16 Length,\r
667 IN UINT32 MappingCount,\r
668 IN UINT32 MappingOffset\r
669 )\r
ee4dc24f
RN
670{\r
671 ParseAcpi (\r
672 TRUE,\r
673 2,\r
674 "PMCG Node",\r
675 Ptr,\r
676 Length,\r
677 PARSER_PARAMS (IortNodePmcgParser)\r
62cefaf4 678 );\r
ee4dc24f 679\r
62cefaf4
KK
680 DumpIortNodeIdMappings (\r
681 Ptr + MappingOffset,\r
682 Length - MappingOffset,\r
683 MappingCount\r
684 );\r
ee4dc24f
RN
685}\r
686\r
cd67efa1
SM
687/**\r
688 This function parses the IORT RMR Node Memory Range Descriptor array.\r
689\r
690 @param [in] Ptr Pointer to the start of the Memory Range Descriptor\r
691 array.\r
692 @param [in] Length Length of the buffer.\r
693 @param [in] DescCount Memory Range Descriptor count.\r
694**/\r
695STATIC\r
696VOID\r
697DumpIortNodeRmrMemRangeDesc (\r
698 IN UINT8 *Ptr,\r
699 IN UINT32 Length,\r
700 IN UINT32 DescCount\r
701 )\r
702{\r
703 UINT32 Index;\r
704 UINT32 Offset;\r
705 CHAR8 Buffer[40]; // Used for AsciiName param of ParseAcpi\r
706\r
707 Index = 0;\r
708 Offset = 0;\r
709\r
710 while ((Index < DescCount) &&\r
711 (Offset < Length))\r
712 {\r
713 AsciiSPrint (\r
714 Buffer,\r
715 sizeof (Buffer),\r
716 "Mem range Descriptor [%d]",\r
717 Index\r
718 );\r
719 Offset += ParseAcpi (\r
720 TRUE,\r
721 4,\r
722 Buffer,\r
723 Ptr + Offset,\r
724 Length - Offset,\r
725 PARSER_PARAMS (IortNodeRmrMemRangeDescParser)\r
726 );\r
727 Index++;\r
728 }\r
729}\r
730\r
731/**\r
732 This function parses the IORT RMR node.\r
733\r
734 @param [in] Ptr Pointer to the start of the buffer.\r
735 @param [in] Length Length of the buffer.\r
736 @param [in] MappingCount The ID Mapping count.\r
737 @param [in] MappingOffset The offset of the ID Mapping array\r
738 from the start of the IORT table.\r
739**/\r
740STATIC\r
741VOID\r
742DumpIortNodeRmr (\r
743 IN UINT8 *Ptr,\r
744 IN UINT16 Length,\r
745 IN UINT32 MappingCount,\r
746 IN UINT32 MappingOffset\r
747 )\r
748{\r
749 ParseAcpi (\r
750 TRUE,\r
751 2,\r
752 "RMR Node",\r
753 Ptr,\r
754 Length,\r
755 PARSER_PARAMS (IortNodeRmrParser)\r
756 );\r
757\r
758 if (*IortNodeRevision == EFI_ACPI_IORT_RMR_NODE_REVISION_02) {\r
759 IncrementErrorCount ();\r
760 Print (\r
761 L"ERROR: RMR node Rev 2 (defined in IORT Rev E.c) must not be used."\r
762 L" IORT tabe Revision E.c is deprecated and must not be used.\n"\r
763 );\r
764 }\r
765\r
766 DumpIortNodeIdMappings (\r
767 Ptr + MappingOffset,\r
768 Length - MappingOffset,\r
769 MappingCount\r
770 );\r
771\r
772 DumpIortNodeRmrMemRangeDesc (\r
773 Ptr + (*RmrMemDescOffset),\r
774 Length - (*RmrMemDescOffset),\r
775 *RmrMemDescCount\r
776 );\r
777}\r
778\r
a6eaba4d
DB
779/**\r
780 This function parses the ACPI IORT table.\r
cd67efa1
SM
781 When trace is enabled this function parses the IORT table and traces the ACPI\r
782 fields.\r
ee4dc24f
RN
783\r
784 This function also parses the following nodes:\r
785 - ITS Group\r
786 - Named Component\r
787 - Root Complex\r
788 - SMMUv1/2\r
789 - SMMUv3\r
790 - PMCG\r
cd67efa1 791 - RMR\r
ee4dc24f
RN
792\r
793 This function also performs validation of the ACPI table fields.\r
794\r
795 @param [in] Trace If TRUE, trace the ACPI fields.\r
796 @param [in] Ptr Pointer to the start of the buffer.\r
797 @param [in] AcpiTableLength Length of the ACPI table.\r
798 @param [in] AcpiTableRevision Revision of the ACPI table.\r
a6eaba4d 799**/\r
ee4dc24f
RN
800VOID\r
801EFIAPI\r
802ParseAcpiIort (\r
47d20b54
MK
803 IN BOOLEAN Trace,\r
804 IN UINT8 *Ptr,\r
805 IN UINT32 AcpiTableLength,\r
806 IN UINT8 AcpiTableRevision\r
ee4dc24f
RN
807 )\r
808{\r
47d20b54
MK
809 UINT32 Offset;\r
810 UINT32 Index;\r
811 UINT8 *NodePtr;\r
ee4dc24f
RN
812\r
813 if (!Trace) {\r
814 return;\r
815 }\r
816\r
cd67efa1
SM
817 if ((AcpiTableRevision > EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00) &&\r
818 (AcpiTableRevision < EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05))\r
819 {\r
820 Print (\r
821 L"ERROR: Parsing not supported for IORT tabe Revision E, E.<a,b,c>.\n"\r
822 );\r
823 if (AcpiTableRevision == EFI_ACPI_IO_REMAPPING_TABLE_REVISION_04) {\r
824 IncrementErrorCount ();\r
825 Print (\r
826 L"ERROR: IORT tabe Revision E.c is deprecated and must not be used.\n"\r
827 );\r
828 }\r
829\r
830 return;\r
831 }\r
832\r
ee4dc24f
RN
833 ParseAcpi (\r
834 TRUE,\r
835 0,\r
836 "IORT",\r
837 Ptr,\r
838 AcpiTableLength,\r
839 PARSER_PARAMS (IortParser)\r
840 );\r
62cefaf4 841\r
ea26838a
KK
842 // Check if the values used to control the parsing logic have been\r
843 // successfully read.\r
844 if ((IortNodeCount == NULL) ||\r
47d20b54
MK
845 (IortNodeOffset == NULL))\r
846 {\r
ea26838a
KK
847 IncrementErrorCount ();\r
848 Print (\r
849 L"ERROR: Insufficient table length. AcpiTableLength = %d.\n",\r
850 AcpiTableLength\r
851 );\r
852 return;\r
853 }\r
854\r
47d20b54 855 Offset = *IortNodeOffset;\r
ee4dc24f 856 NodePtr = Ptr + Offset;\r
47d20b54 857 Index = 0;\r
ee4dc24f 858\r
62cefaf4
KK
859 // Parse the specified number of IORT nodes or the IORT table buffer length.\r
860 // Whichever is minimum.\r
861 while ((Index++ < *IortNodeCount) &&\r
47d20b54
MK
862 (Offset < AcpiTableLength))\r
863 {\r
ee4dc24f
RN
864 // Parse the IORT Node Header\r
865 ParseAcpi (\r
866 FALSE,\r
867 0,\r
868 "IORT Node Header",\r
869 NodePtr,\r
62cefaf4 870 AcpiTableLength - Offset,\r
ee4dc24f
RN
871 PARSER_PARAMS (IortNodeHeaderParser)\r
872 );\r
62cefaf4 873\r
ea26838a
KK
874 // Check if the values used to control the parsing logic have been\r
875 // successfully read.\r
876 if ((IortNodeType == NULL) ||\r
877 (IortNodeLength == NULL) ||\r
878 (IortIdMappingCount == NULL) ||\r
47d20b54
MK
879 (IortIdMappingOffset == NULL))\r
880 {\r
ea26838a
KK
881 IncrementErrorCount ();\r
882 Print (\r
883 L"ERROR: Insufficient remaining table buffer length to read the " \\r
47d20b54 884 L"IORT node header. Length = %d.\n",\r
ea26838a
KK
885 AcpiTableLength - Offset\r
886 );\r
887 return;\r
888 }\r
889\r
b8504826
KK
890 // Validate IORT Node length\r
891 if ((*IortNodeLength == 0) ||\r
47d20b54
MK
892 ((Offset + (*IortNodeLength)) > AcpiTableLength))\r
893 {\r
ee4dc24f 894 IncrementErrorCount ();\r
62cefaf4 895 Print (\r
b8504826 896 L"ERROR: Invalid IORT Node length. " \\r
47d20b54 897 L"Length = %d. Offset = %d. AcpiTableLength = %d.\n",\r
62cefaf4 898 *IortNodeLength,\r
b8504826
KK
899 Offset,\r
900 AcpiTableLength\r
62cefaf4 901 );\r
ee4dc24f
RN
902 return;\r
903 }\r
904\r
905 PrintFieldName (2, L"* Node Offset *");\r
906 Print (L"0x%x\n", Offset);\r
907\r
908 switch (*IortNodeType) {\r
f17dad04 909 case EFI_ACPI_IORT_TYPE_ITS_GROUP:\r
ee4dc24f
RN
910 DumpIortNodeIts (\r
911 NodePtr,\r
912 *IortNodeLength\r
913 );\r
914 break;\r
f17dad04 915 case EFI_ACPI_IORT_TYPE_NAMED_COMP:\r
ee4dc24f
RN
916 DumpIortNodeNamedComponent (\r
917 NodePtr,\r
918 *IortNodeLength,\r
919 *IortIdMappingCount,\r
920 *IortIdMappingOffset\r
921 );\r
922 break;\r
f17dad04 923 case EFI_ACPI_IORT_TYPE_ROOT_COMPLEX:\r
ee4dc24f
RN
924 DumpIortNodeRootComplex (\r
925 NodePtr,\r
926 *IortNodeLength,\r
927 *IortIdMappingCount,\r
928 *IortIdMappingOffset\r
929 );\r
930 break;\r
f17dad04 931 case EFI_ACPI_IORT_TYPE_SMMUv1v2:\r
ee4dc24f
RN
932 DumpIortNodeSmmuV1V2 (\r
933 NodePtr,\r
934 *IortNodeLength,\r
935 *IortIdMappingCount,\r
936 *IortIdMappingOffset\r
937 );\r
938 break;\r
f17dad04 939 case EFI_ACPI_IORT_TYPE_SMMUv3:\r
ee4dc24f
RN
940 DumpIortNodeSmmuV3 (\r
941 NodePtr,\r
942 *IortNodeLength,\r
943 *IortIdMappingCount,\r
944 *IortIdMappingOffset\r
945 );\r
946 break;\r
f17dad04 947 case EFI_ACPI_IORT_TYPE_PMCG:\r
ee4dc24f
RN
948 DumpIortNodePmcg (\r
949 NodePtr,\r
950 *IortNodeLength,\r
951 *IortIdMappingCount,\r
952 *IortIdMappingOffset\r
47d20b54 953 );\r
ee4dc24f 954 break;\r
cd67efa1
SM
955 case EFI_ACPI_IORT_TYPE_RMR:\r
956 DumpIortNodeRmr (\r
957 NodePtr,\r
958 *IortNodeLength,\r
959 *IortIdMappingCount,\r
960 *IortIdMappingOffset\r
961 );\r
962 break;\r
ee4dc24f
RN
963 default:\r
964 IncrementErrorCount ();\r
965 Print (L"ERROR: Unsupported IORT Node type = %d\n", *IortNodeType);\r
966 } // switch\r
967\r
968 NodePtr += (*IortNodeLength);\r
47d20b54 969 Offset += (*IortNodeLength);\r
ee4dc24f
RN
970 } // while\r
971}\r