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