]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pptt/PpttParser.c
ShellPkg: acpiview: Prevent infinite loop if structure length is 0
[mirror_edk2.git] / ShellPkg / Library / UefiShellAcpiViewCommandLib / Parsers / Pptt / PpttParser.c
CommitLineData
d4d2fdf2
KK
1/** @file\r
2 PPTT table parser\r
3\r
b8504826 4 Copyright (c) 2019 - 2020, ARM Limited. All rights reserved.\r
56ba3746 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
d4d2fdf2
KK
6\r
7 @par Reference(s):\r
5a27f7a2
KK
8 - ACPI 6.3 Specification - January 2019\r
9 - ARM Architecture Reference Manual ARMv8 (D.a)\r
d4d2fdf2
KK
10**/\r
11\r
12#include <Library/PrintLib.h>\r
13#include <Library/UefiLib.h>\r
14#include "AcpiParser.h"\r
5a27f7a2
KK
15#include "AcpiView.h"\r
16#include "PpttParser.h"\r
d4d2fdf2
KK
17\r
18// Local variables\r
19STATIC CONST UINT8* ProcessorTopologyStructureType;\r
20STATIC CONST UINT8* ProcessorTopologyStructureLength;\r
21STATIC CONST UINT32* NumberOfPrivateResources;\r
22STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;\r
23\r
24/**\r
5a27f7a2
KK
25 This function validates the Cache Type Structure (Type 1) 'Number of sets'\r
26 field.\r
27\r
28 @param [in] Ptr Pointer to the start of the field data.\r
29 @param [in] Context Pointer to context specific information e.g. this\r
30 could be a pointer to the ACPI table header.\r
d4d2fdf2 31**/\r
5a27f7a2
KK
32STATIC\r
33VOID\r
34EFIAPI\r
35ValidateCacheNumberOfSets (\r
36 IN UINT8* Ptr,\r
37 IN VOID* Context\r
38 )\r
39{\r
40 UINT32 NumberOfSets;\r
41 NumberOfSets = *(UINT32*)Ptr;\r
42\r
43 if (NumberOfSets == 0) {\r
44 IncrementErrorCount ();\r
45 Print (L"\nERROR: Cache number of sets must be greater than 0");\r
46 return;\r
47 }\r
48\r
49#if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)\r
50 if (NumberOfSets > PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX) {\r
51 IncrementErrorCount ();\r
52 Print (\r
53 L"\nERROR: When ARMv8.3-CCIDX is implemented the maximum cache number of "\r
54 L"sets must be less than or equal to %d",\r
55 PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX\r
56 );\r
57 return;\r
58 }\r
59\r
60 if (NumberOfSets > PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX) {\r
61 IncrementWarningCount ();\r
62 Print (\r
63 L"\nWARNING: Without ARMv8.3-CCIDX, the maximum cache number of sets "\r
64 L"must be less than or equal to %d. Ignore this message if "\r
65 L"ARMv8.3-CCIDX is implemented",\r
66 PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX\r
67 );\r
68 return;\r
69 }\r
70#endif\r
71\r
72}\r
73\r
74/**\r
75 This function validates the Cache Type Structure (Type 1) 'Associativity'\r
76 field.\r
77\r
78 @param [in] Ptr Pointer to the start of the field data.\r
79 @param [in] Context Pointer to context specific information e.g. this\r
80 could be a pointer to the ACPI table header.\r
81**/\r
82STATIC\r
83VOID\r
84EFIAPI\r
85ValidateCacheAssociativity (\r
86 IN UINT8* Ptr,\r
87 IN VOID* Context\r
88 )\r
89{\r
90 UINT8 Associativity;\r
91 Associativity = *(UINT8*)Ptr;\r
92\r
93 if (Associativity == 0) {\r
94 IncrementErrorCount ();\r
95 Print (L"\nERROR: Cache associativity must be greater than 0");\r
96 return;\r
97 }\r
98}\r
d4d2fdf2
KK
99\r
100/**\r
101 This function validates the Cache Type Structure (Type 1) Line size field.\r
102\r
103 @param [in] Ptr Pointer to the start of the field data.\r
104 @param [in] Context Pointer to context specific information e.g. this\r
105 could be a pointer to the ACPI table header.\r
106**/\r
107STATIC\r
108VOID\r
109EFIAPI\r
110ValidateCacheLineSize (\r
111 IN UINT8* Ptr,\r
112 IN VOID* Context\r
113 )\r
114{\r
115#if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)\r
116 // Reference: ARM Architecture Reference Manual ARMv8 (D.a)\r
117 // Section D12.2.25: CCSIDR_EL1, Current Cache Size ID Register\r
118 // LineSize, bits [2:0]\r
119 // (Log2(Number of bytes in cache line)) - 4.\r
120\r
121 UINT16 LineSize;\r
122 LineSize = *(UINT16*)Ptr;\r
123\r
5a27f7a2
KK
124 if ((LineSize < PPTT_ARM_CACHE_LINE_SIZE_MIN) ||\r
125 (LineSize > PPTT_ARM_CACHE_LINE_SIZE_MAX)) {\r
d4d2fdf2
KK
126 IncrementErrorCount ();\r
127 Print (\r
5a27f7a2
KK
128 L"\nERROR: The cache line size must be between %d and %d bytes"\r
129 L" on ARM Platforms.",\r
130 PPTT_ARM_CACHE_LINE_SIZE_MIN,\r
131 PPTT_ARM_CACHE_LINE_SIZE_MAX\r
d4d2fdf2
KK
132 );\r
133 return;\r
134 }\r
135\r
136 if ((LineSize & (LineSize - 1)) != 0) {\r
137 IncrementErrorCount ();\r
138 Print (L"\nERROR: The cache line size is not a power of 2.");\r
139 }\r
140#endif\r
141}\r
142\r
143/**\r
144 This function validates the Cache Type Structure (Type 1) Attributes field.\r
145\r
146 @param [in] Ptr Pointer to the start of the field data.\r
147 @param [in] Context Pointer to context specific information e.g. this\r
148 could be a pointer to the ACPI table header.\r
149**/\r
150STATIC\r
151VOID\r
152EFIAPI\r
153ValidateCacheAttributes (\r
154 IN UINT8* Ptr,\r
155 IN VOID* Context\r
156 )\r
157{\r
d4d2fdf2
KK
158 // Reference: Advanced Configuration and Power Interface (ACPI) Specification\r
159 // Version 6.2 Errata A, September 2017\r
160 // Table 5-153: Cache Type Structure\r
d4d2fdf2
KK
161 UINT8 Attributes;\r
162 Attributes = *(UINT8*)Ptr;\r
163\r
164 if ((Attributes & 0xE0) != 0) {\r
165 IncrementErrorCount ();\r
166 Print (\r
167 L"\nERROR: Attributes bits [7:5] are reserved and must be zero.",\r
168 Attributes\r
169 );\r
170 return;\r
171 }\r
d4d2fdf2
KK
172}\r
173\r
5a27f7a2
KK
174/**\r
175 An ACPI_PARSER array describing the ACPI PPTT Table.\r
176**/\r
177STATIC CONST ACPI_PARSER PpttParser[] = {\r
178 PARSE_ACPI_HEADER (&AcpiHdrInfo)\r
179};\r
180\r
d4d2fdf2
KK
181/**\r
182 An ACPI_PARSER array describing the processor topology structure header.\r
183**/\r
184STATIC CONST ACPI_PARSER ProcessorTopologyStructureHeaderParser[] = {\r
185 {L"Type", 1, 0, NULL, NULL, (VOID**)&ProcessorTopologyStructureType,\r
186 NULL, NULL},\r
187 {L"Length", 1, 1, NULL, NULL, (VOID**)&ProcessorTopologyStructureLength,\r
188 NULL, NULL},\r
189 {L"Reserved", 2, 2, NULL, NULL, NULL, NULL, NULL}\r
190};\r
191\r
192/**\r
193 An ACPI_PARSER array describing the Processor Hierarchy Node Structure - Type 0.\r
194**/\r
195STATIC CONST ACPI_PARSER ProcessorHierarchyNodeStructureParser[] = {\r
196 {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
197 {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},\r
198 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},\r
199\r
200 {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
201 {L"Parent", 4, 8, L"0x%x", NULL, NULL, NULL, NULL},\r
202 {L"ACPI Processor ID", 4, 12, L"0x%x", NULL, NULL, NULL, NULL},\r
203 {L"Number of private resources", 4, 16, L"%d", NULL,\r
204 (VOID**)&NumberOfPrivateResources, NULL, NULL}\r
205};\r
206\r
207/**\r
208 An ACPI_PARSER array describing the Cache Type Structure - Type 1.\r
209**/\r
210STATIC CONST ACPI_PARSER CacheTypeStructureParser[] = {\r
211 {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
212 {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},\r
213 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},\r
214\r
215 {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
216 {L"Next Level of Cache", 4, 8, L"0x%x", NULL, NULL, NULL, NULL},\r
217 {L"Size", 4, 12, L"0x%x", NULL, NULL, NULL, NULL},\r
5a27f7a2
KK
218 {L"Number of sets", 4, 16, L"%d", NULL, NULL, ValidateCacheNumberOfSets, NULL},\r
219 {L"Associativity", 1, 20, L"%d", NULL, NULL, ValidateCacheAssociativity, NULL},\r
d4d2fdf2
KK
220 {L"Attributes", 1, 21, L"0x%x", NULL, NULL, ValidateCacheAttributes, NULL},\r
221 {L"Line size", 2, 22, L"%d", NULL, NULL, ValidateCacheLineSize, NULL}\r
222};\r
223\r
224/**\r
225 An ACPI_PARSER array describing the ID Type Structure - Type 2.\r
226**/\r
227STATIC CONST ACPI_PARSER IdStructureParser[] = {\r
228 {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
229 {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},\r
230 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},\r
231\r
7b84de93 232 {L"VENDOR_ID", 4, 4, NULL, Dump4Chars, NULL, NULL, NULL},\r
d4d2fdf2
KK
233 {L"LEVEL_1_ID", 8, 8, L"0x%x", NULL, NULL, NULL, NULL},\r
234 {L"LEVEL_2_ID", 8, 16, L"0x%x", NULL, NULL, NULL, NULL},\r
235 {L"MAJOR_REV", 2, 24, L"0x%x", NULL, NULL, NULL, NULL},\r
236 {L"MINOR_REV", 2, 26, L"0x%x", NULL, NULL, NULL, NULL},\r
237 {L"SPIN_REV", 2, 28, L"0x%x", NULL, NULL, NULL, NULL},\r
238};\r
239\r
240/**\r
241 This function parses the Processor Hierarchy Node Structure (Type 0).\r
242\r
243 @param [in] Ptr Pointer to the start of the Processor Hierarchy Node\r
244 Structure data.\r
245 @param [in] Length Length of the Processor Hierarchy Node Structure.\r
246**/\r
247STATIC\r
248VOID\r
249DumpProcessorHierarchyNodeStructure (\r
250 IN UINT8* Ptr,\r
251 IN UINT8 Length\r
252 )\r
253{\r
f34b38fa 254 UINT32 Offset;\r
d4d2fdf2
KK
255 UINT32 Index;\r
256 CHAR16 Buffer[OUTPUT_FIELD_COLUMN_WIDTH];\r
257\r
258 Offset = ParseAcpi (\r
259 TRUE,\r
260 2,\r
261 "Processor Hierarchy Node Structure",\r
262 Ptr,\r
263 Length,\r
264 PARSER_PARAMS (ProcessorHierarchyNodeStructureParser)\r
265 );\r
266\r
84a534b4
KK
267 // Check if the values used to control the parsing logic have been\r
268 // successfully read.\r
269 if (NumberOfPrivateResources == NULL) {\r
270 IncrementErrorCount ();\r
271 Print (\r
272 L"ERROR: Insufficient Processor Hierarchy Node length. Length = %d.\n",\r
273 Length\r
274 );\r
275 return;\r
276 }\r
277\r
5f066122
KK
278 // Make sure the Private Resource array lies inside this structure\r
279 if (Offset + (*NumberOfPrivateResources * sizeof (UINT32)) > Length) {\r
280 IncrementErrorCount ();\r
281 Print (\r
282 L"ERROR: Invalid Number of Private Resources. " \\r
283 L"PrivateResourceCount = %d. RemainingBufferLength = %d. " \\r
284 L"Parsing of this structure aborted.\n",\r
285 *NumberOfPrivateResources,\r
286 Length - Offset\r
287 );\r
288 return;\r
289 }\r
290\r
d4d2fdf2 291 Index = 0;\r
5f066122
KK
292\r
293 // Parse the specified number of private resource references or the Processor\r
294 // Hierarchy Node length. Whichever is minimum.\r
d4d2fdf2
KK
295 while (Index < *NumberOfPrivateResources) {\r
296 UnicodeSPrint (\r
297 Buffer,\r
298 sizeof (Buffer),\r
299 L"Private resources [%d]",\r
300 Index\r
301 );\r
302\r
303 PrintFieldName (4, Buffer);\r
304 Print (\r
305 L"0x%x\n",\r
5f066122 306 *((UINT32*)(Ptr + Offset))\r
d4d2fdf2
KK
307 );\r
308\r
5f066122 309 Offset += sizeof (UINT32);\r
d4d2fdf2
KK
310 Index++;\r
311 }\r
312}\r
313\r
314/**\r
315 This function parses the Cache Type Structure (Type 1).\r
316\r
317 @param [in] Ptr Pointer to the start of the Cache Type Structure data.\r
318 @param [in] Length Length of the Cache Type Structure.\r
319**/\r
320STATIC\r
321VOID\r
322DumpCacheTypeStructure (\r
323 IN UINT8* Ptr,\r
324 IN UINT8 Length\r
325 )\r
326{\r
327 ParseAcpi (\r
328 TRUE,\r
329 2,\r
330 "Cache Type Structure",\r
331 Ptr,\r
332 Length,\r
333 PARSER_PARAMS (CacheTypeStructureParser)\r
334 );\r
335}\r
336\r
337/**\r
338 This function parses the ID Structure (Type 2).\r
339\r
340 @param [in] Ptr Pointer to the start of the ID Structure data.\r
341 @param [in] Length Length of the ID Structure.\r
342**/\r
343STATIC\r
344VOID\r
345DumpIDStructure (\r
346 IN UINT8* Ptr,\r
347 IN UINT8 Length\r
348 )\r
349{\r
350 ParseAcpi (\r
351 TRUE,\r
352 2,\r
353 "ID Structure",\r
354 Ptr,\r
355 Length,\r
356 PARSER_PARAMS (IdStructureParser)\r
357 );\r
358}\r
359\r
360/**\r
361 This function parses the ACPI PPTT table.\r
362 When trace is enabled this function parses the PPTT table and\r
363 traces the ACPI table fields.\r
364\r
365 This function parses the following processor topology structures:\r
366 - Processor hierarchy node structure (Type 0)\r
367 - Cache Type Structure (Type 1)\r
368 - ID structure (Type 2)\r
369\r
370 This function also performs validation of the ACPI table fields.\r
371\r
372 @param [in] Trace If TRUE, trace the ACPI fields.\r
373 @param [in] Ptr Pointer to the start of the buffer.\r
374 @param [in] AcpiTableLength Length of the ACPI table.\r
375 @param [in] AcpiTableRevision Revision of the ACPI table.\r
376**/\r
377VOID\r
378EFIAPI\r
379ParseAcpiPptt (\r
380 IN BOOLEAN Trace,\r
381 IN UINT8* Ptr,\r
382 IN UINT32 AcpiTableLength,\r
383 IN UINT8 AcpiTableRevision\r
384 )\r
385{\r
386 UINT32 Offset;\r
387 UINT8* ProcessorTopologyStructurePtr;\r
388\r
389 if (!Trace) {\r
390 return;\r
391 }\r
392\r
393 Offset = ParseAcpi (\r
394 TRUE,\r
395 0,\r
396 "PPTT",\r
397 Ptr,\r
398 AcpiTableLength,\r
399 PARSER_PARAMS (PpttParser)\r
400 );\r
84a534b4 401\r
d4d2fdf2
KK
402 ProcessorTopologyStructurePtr = Ptr + Offset;\r
403\r
404 while (Offset < AcpiTableLength) {\r
405 // Parse Processor Hierarchy Node Structure to obtain Type and Length.\r
406 ParseAcpi (\r
407 FALSE,\r
408 0,\r
409 NULL,\r
410 ProcessorTopologyStructurePtr,\r
5f066122 411 AcpiTableLength - Offset,\r
d4d2fdf2
KK
412 PARSER_PARAMS (ProcessorTopologyStructureHeaderParser)\r
413 );\r
414\r
84a534b4
KK
415 // Check if the values used to control the parsing logic have been\r
416 // successfully read.\r
417 if ((ProcessorTopologyStructureType == NULL) ||\r
418 (ProcessorTopologyStructureLength == NULL)) {\r
419 IncrementErrorCount ();\r
420 Print (\r
421 L"ERROR: Insufficient remaining table buffer length to read the " \\r
422 L"processor topology structure header. Length = %d.\n",\r
423 AcpiTableLength - Offset\r
424 );\r
425 return;\r
426 }\r
427\r
b8504826
KK
428 // Validate Processor Topology Structure length\r
429 if ((*ProcessorTopologyStructureLength == 0) ||\r
430 ((Offset + (*ProcessorTopologyStructureLength)) > AcpiTableLength)) {\r
d4d2fdf2
KK
431 IncrementErrorCount ();\r
432 Print (\r
b8504826
KK
433 L"ERROR: Invalid Processor Topology Structure length. " \\r
434 L"Length = %d. Offset = %d. AcpiTableLength = %d.\n",\r
5f066122 435 *ProcessorTopologyStructureLength,\r
b8504826
KK
436 Offset,\r
437 AcpiTableLength\r
d4d2fdf2 438 );\r
5f066122 439 return;\r
d4d2fdf2
KK
440 }\r
441\r
442 PrintFieldName (2, L"* Structure Offset *");\r
443 Print (L"0x%x\n", Offset);\r
444\r
445 switch (*ProcessorTopologyStructureType) {\r
446 case EFI_ACPI_6_2_PPTT_TYPE_PROCESSOR:\r
447 DumpProcessorHierarchyNodeStructure (\r
448 ProcessorTopologyStructurePtr,\r
449 *ProcessorTopologyStructureLength\r
450 );\r
451 break;\r
452 case EFI_ACPI_6_2_PPTT_TYPE_CACHE:\r
453 DumpCacheTypeStructure (\r
454 ProcessorTopologyStructurePtr,\r
455 *ProcessorTopologyStructureLength\r
456 );\r
457 break;\r
458 case EFI_ACPI_6_2_PPTT_TYPE_ID:\r
459 DumpIDStructure (\r
460 ProcessorTopologyStructurePtr,\r
461 *ProcessorTopologyStructureLength\r
462 );\r
463 break;\r
464 default:\r
465 IncrementErrorCount ();\r
466 Print (\r
467 L"ERROR: Unknown processor topology structure:"\r
468 L" Type = %d, Length = %d\n",\r
469 *ProcessorTopologyStructureType,\r
470 *ProcessorTopologyStructureLength\r
471 );\r
472 }\r
473\r
474 ProcessorTopologyStructurePtr += *ProcessorTopologyStructureLength;\r
475 Offset += *ProcessorTopologyStructureLength;\r
476 } // while\r
477}\r