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