]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pptt/PpttParser.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 CONST EFI_ACPI_6_4_PPTT_STRUCTURE_CACHE_FLAGS *CacheFlags;
24 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;
25
26 #if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)
27
28 /**
29 Increment the error count and print an error that a required flag is missing.
30
31 @param [in] FlagName Name of the missing flag.
32 **/
33 STATIC
34 VOID
35 EFIAPI
36 LogCacheFlagError (
37 IN CONST CHAR16 *FlagName
38 )
39 {
40 IncrementErrorCount ();
41 Print (
42 L"\nERROR: On Arm based systems, all cache properties must be"
43 L" provided in the cache type structure."
44 L" Missing '%s' flag.",
45 FlagName
46 );
47 }
48
49 #endif
50
51 /**
52 This function validates the Cache Type Structure (Type 1) Cache Flags field.
53
54 @param [in] Ptr Pointer to the start of the field data.
55 @param [in] Context Pointer to context specific information e.g. this
56 could be a pointer to the ACPI table header.
57 **/
58 STATIC
59 VOID
60 EFIAPI
61 ValidateCacheFlags (
62 IN UINT8 *Ptr,
63 IN VOID *Context
64 )
65 {
66 #if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)
67 CacheFlags = (EFI_ACPI_6_4_PPTT_STRUCTURE_CACHE_FLAGS *)Ptr;
68
69 if (CacheFlags == NULL) {
70 IncrementErrorCount ();
71 Print (L"\nERROR: Cache Structure Flags were not successfully read.");
72 return;
73 }
74
75 if (CacheFlags->SizePropertyValid == EFI_ACPI_6_4_PPTT_CACHE_SIZE_INVALID) {
76 LogCacheFlagError (L"Size Property Valid");
77 }
78
79 if (CacheFlags->NumberOfSetsValid == EFI_ACPI_6_4_PPTT_NUMBER_OF_SETS_INVALID) {
80 LogCacheFlagError (L"Number Of Sets Valid");
81 }
82
83 if (CacheFlags->AssociativityValid == EFI_ACPI_6_4_PPTT_ASSOCIATIVITY_INVALID) {
84 LogCacheFlagError (L"Associativity Valid");
85 }
86
87 if (CacheFlags->AllocationTypeValid == EFI_ACPI_6_4_PPTT_ALLOCATION_TYPE_INVALID) {
88 LogCacheFlagError (L"Allocation Type Valid");
89 }
90
91 if (CacheFlags->CacheTypeValid == EFI_ACPI_6_4_PPTT_CACHE_TYPE_INVALID) {
92 LogCacheFlagError (L"Cache Type Valid");
93 }
94
95 if (CacheFlags->WritePolicyValid == EFI_ACPI_6_4_PPTT_WRITE_POLICY_INVALID) {
96 LogCacheFlagError (L"Write Policy Valid");
97 }
98
99 if (CacheFlags->LineSizeValid == EFI_ACPI_6_4_PPTT_LINE_SIZE_INVALID) {
100 LogCacheFlagError (L"Line Size Valid");
101 }
102
103 // Cache ID was only introduced in revision 3
104 if (*(AcpiHdrInfo.Revision) >= 3) {
105 if (CacheFlags->CacheIdValid == EFI_ACPI_6_4_PPTT_CACHE_ID_INVALID) {
106 LogCacheFlagError (L"Cache Id Valid");
107 }
108 }
109
110 #endif
111 }
112
113 /**
114 This function validates the Cache Type Structure (Type 1) 'Number of sets'
115 field.
116
117 @param [in] Ptr Pointer to the start of the field data.
118 @param [in] Context Pointer to context specific information e.g. this
119 could be a pointer to the ACPI table header.
120 **/
121 STATIC
122 VOID
123 EFIAPI
124 ValidateCacheNumberOfSets (
125 IN UINT8 *Ptr,
126 IN VOID *Context
127 )
128 {
129 UINT32 NumberOfSets;
130
131 NumberOfSets = *(UINT32 *)Ptr;
132
133 if (NumberOfSets == 0) {
134 IncrementErrorCount ();
135 Print (L"\nERROR: Cache number of sets must be greater than 0");
136 return;
137 }
138
139 #if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)
140 if (NumberOfSets > PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX) {
141 IncrementErrorCount ();
142 Print (
143 L"\nERROR: When ARMv8.3-CCIDX is implemented the maximum cache number of "
144 L"sets must be less than or equal to %d",
145 PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX
146 );
147 return;
148 }
149
150 if (NumberOfSets > PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX) {
151 IncrementWarningCount ();
152 Print (
153 L"\nWARNING: Without ARMv8.3-CCIDX, the maximum cache number of sets "
154 L"must be less than or equal to %d. Ignore this message if "
155 L"ARMv8.3-CCIDX is implemented",
156 PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX
157 );
158 return;
159 }
160
161 #endif
162 }
163
164 /**
165 This function validates the Cache Type Structure (Type 1) 'Associativity'
166 field.
167
168 @param [in] Ptr Pointer to the start of the field data.
169 @param [in] Context Pointer to context specific information e.g. this
170 could be a pointer to the ACPI table header.
171 **/
172 STATIC
173 VOID
174 EFIAPI
175 ValidateCacheAssociativity (
176 IN UINT8 *Ptr,
177 IN VOID *Context
178 )
179 {
180 UINT8 Associativity;
181
182 Associativity = *(UINT8 *)Ptr;
183
184 if (Associativity == 0) {
185 IncrementErrorCount ();
186 Print (L"\nERROR: Cache associativity must be greater than 0");
187 return;
188 }
189 }
190
191 /**
192 This function validates the Cache Type Structure (Type 1) Line size field.
193
194 @param [in] Ptr Pointer to the start of the field data.
195 @param [in] Context Pointer to context specific information e.g. this
196 could be a pointer to the ACPI table header.
197 **/
198 STATIC
199 VOID
200 EFIAPI
201 ValidateCacheLineSize (
202 IN UINT8 *Ptr,
203 IN VOID *Context
204 )
205 {
206 #if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)
207 // Reference: ARM Architecture Reference Manual ARMv8 (D.a)
208 // Section D12.2.25: CCSIDR_EL1, Current Cache Size ID Register
209 // LineSize, bits [2:0]
210 // (Log2(Number of bytes in cache line)) - 4.
211
212 UINT16 LineSize;
213 LineSize = *(UINT16 *)Ptr;
214
215 if ((LineSize < PPTT_ARM_CACHE_LINE_SIZE_MIN) ||
216 (LineSize > PPTT_ARM_CACHE_LINE_SIZE_MAX))
217 {
218 IncrementErrorCount ();
219 Print (
220 L"\nERROR: The cache line size must be between %d and %d bytes"
221 L" on ARM Platforms.",
222 PPTT_ARM_CACHE_LINE_SIZE_MIN,
223 PPTT_ARM_CACHE_LINE_SIZE_MAX
224 );
225 return;
226 }
227
228 if ((LineSize & (LineSize - 1)) != 0) {
229 IncrementErrorCount ();
230 Print (L"\nERROR: The cache line size is not a power of 2.");
231 }
232
233 #endif
234 }
235
236 /**
237 This function validates the Cache Type Structure (Type 1) Cache ID field.
238
239 @param [in] Ptr Pointer to the start of the field data.
240 @param [in] Context Pointer to context specific information e.g. this
241 could be a pointer to the ACPI table header.
242 **/
243 STATIC
244 VOID
245 EFIAPI
246 ValidateCacheId (
247 IN UINT8 *Ptr,
248 IN VOID *Context
249 )
250 {
251 UINT32 CacheId;
252
253 CacheId = *(UINT32 *)Ptr;
254
255 // Cache ID was only introduced in revision 3
256 if (*(AcpiHdrInfo.Revision) < 3) {
257 return;
258 }
259
260 if (CacheFlags == NULL) {
261 IncrementErrorCount ();
262 Print (L"\nERROR: Cache Structure Flags were not successfully read.");
263 return;
264 }
265
266 if (CacheFlags->CacheIdValid == EFI_ACPI_6_4_PPTT_CACHE_ID_VALID) {
267 if (CacheId == 0) {
268 IncrementErrorCount ();
269 Print (L"\nERROR: 0 is not a valid Cache ID.");
270 return;
271 }
272 }
273 }
274
275 /**
276 This function validates the Cache Type Structure (Type 1) Attributes field.
277
278 @param [in] Ptr Pointer to the start of the field data.
279 @param [in] Context Pointer to context specific information e.g. this
280 could be a pointer to the ACPI table header.
281 **/
282 STATIC
283 VOID
284 EFIAPI
285 ValidateCacheAttributes (
286 IN UINT8 *Ptr,
287 IN VOID *Context
288 )
289 {
290 // Reference: Advanced Configuration and Power Interface (ACPI) Specification
291 // Version 6.4, January 2021
292 // Table 5-140: Cache Type Structure
293 UINT8 Attributes;
294
295 Attributes = *(UINT8 *)Ptr;
296
297 if ((Attributes & 0xE0) != 0) {
298 IncrementErrorCount ();
299 Print (
300 L"\nERROR: Attributes bits [7:5] are reserved and must be zero.",
301 Attributes
302 );
303 return;
304 }
305 }
306
307 /**
308 An ACPI_PARSER array describing the ACPI PPTT Table.
309 **/
310 STATIC CONST ACPI_PARSER PpttParser[] = {
311 PARSE_ACPI_HEADER (&AcpiHdrInfo)
312 };
313
314 /**
315 An ACPI_PARSER array describing the processor topology structure header.
316 **/
317 STATIC CONST ACPI_PARSER ProcessorTopologyStructureHeaderParser[] = {
318 { L"Type", 1, 0, NULL, NULL, (VOID **)&ProcessorTopologyStructureType,
319 NULL, NULL },
320 { L"Length", 1, 1, NULL, NULL, (VOID **)&ProcessorTopologyStructureLength,
321 NULL, NULL },
322 { L"Reserved", 2, 2, NULL, NULL, NULL, NULL,NULL }
323 };
324
325 /**
326 An ACPI_PARSER array describing the Processor Hierarchy Node Structure - Type 0.
327 **/
328 STATIC CONST ACPI_PARSER ProcessorHierarchyNodeStructureParser[] = {
329 { L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
330 { L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
331 { L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL },
332
333 { L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
334 { L"Parent", 4, 8, L"0x%x", NULL, NULL, NULL, NULL },
335 { L"ACPI Processor ID", 4, 12, L"0x%x", NULL, NULL, NULL, NULL },
336 { L"Number of private resources", 4, 16, L"%d", NULL,
337 (VOID **)&NumberOfPrivateResources, NULL, NULL }
338 };
339
340 /**
341 An ACPI_PARSER array describing the Cache Type Structure - Type 1.
342 **/
343 STATIC CONST ACPI_PARSER CacheTypeStructureParser[] = {
344 { L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
345 { L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
346 { L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL },
347
348 { L"Flags", 4, 4, L"0x%x", NULL, (VOID **)&CacheFlags, ValidateCacheFlags,
349 NULL },
350 { L"Next Level of Cache", 4, 8, L"0x%x", NULL, NULL, NULL, NULL },
351 { L"Size", 4, 12, L"0x%x", NULL, NULL, NULL, NULL },
352 { L"Number of sets", 4, 16, L"%d", NULL, NULL, ValidateCacheNumberOfSets, NULL },
353 { L"Associativity", 1, 20, L"%d", NULL, NULL, ValidateCacheAssociativity, NULL },
354 { L"Attributes", 1, 21, L"0x%x", NULL, NULL, ValidateCacheAttributes, NULL },
355 { L"Line size", 2, 22, L"%d", NULL, NULL, ValidateCacheLineSize, NULL },
356 { L"Cache ID", 4, 24, L"%d", NULL, NULL, ValidateCacheId, NULL }
357 };
358
359 /**
360 This function parses the Processor Hierarchy Node Structure (Type 0).
361
362 @param [in] Ptr Pointer to the start of the Processor Hierarchy Node
363 Structure data.
364 @param [in] Length Length of the Processor Hierarchy Node Structure.
365 **/
366 STATIC
367 VOID
368 DumpProcessorHierarchyNodeStructure (
369 IN UINT8 *Ptr,
370 IN UINT8 Length
371 )
372 {
373 UINT32 Offset;
374 UINT32 Index;
375 CHAR16 Buffer[OUTPUT_FIELD_COLUMN_WIDTH];
376
377 Offset = ParseAcpi (
378 TRUE,
379 2,
380 "Processor Hierarchy Node Structure",
381 Ptr,
382 Length,
383 PARSER_PARAMS (ProcessorHierarchyNodeStructureParser)
384 );
385
386 // Check if the values used to control the parsing logic have been
387 // successfully read.
388 if (NumberOfPrivateResources == NULL) {
389 IncrementErrorCount ();
390 Print (
391 L"ERROR: Insufficient Processor Hierarchy Node length. Length = %d.\n",
392 Length
393 );
394 return;
395 }
396
397 // Make sure the Private Resource array lies inside this structure
398 if (Offset + (*NumberOfPrivateResources * sizeof (UINT32)) > Length) {
399 IncrementErrorCount ();
400 Print (
401 L"ERROR: Invalid Number of Private Resources. " \
402 L"PrivateResourceCount = %d. RemainingBufferLength = %d. " \
403 L"Parsing of this structure aborted.\n",
404 *NumberOfPrivateResources,
405 Length - Offset
406 );
407 return;
408 }
409
410 Index = 0;
411
412 // Parse the specified number of private resource references or the Processor
413 // Hierarchy Node length. Whichever is minimum.
414 while (Index < *NumberOfPrivateResources) {
415 UnicodeSPrint (
416 Buffer,
417 sizeof (Buffer),
418 L"Private resources [%d]",
419 Index
420 );
421
422 PrintFieldName (4, Buffer);
423 Print (
424 L"0x%x\n",
425 *((UINT32 *)(Ptr + Offset))
426 );
427
428 Offset += sizeof (UINT32);
429 Index++;
430 }
431 }
432
433 /**
434 This function parses the Cache Type Structure (Type 1).
435
436 @param [in] Ptr Pointer to the start of the Cache Type Structure data.
437 @param [in] Length Length of the Cache Type Structure.
438 **/
439 STATIC
440 VOID
441 DumpCacheTypeStructure (
442 IN UINT8 *Ptr,
443 IN UINT8 Length
444 )
445 {
446 ParseAcpi (
447 TRUE,
448 2,
449 "Cache Type Structure",
450 Ptr,
451 Length,
452 PARSER_PARAMS (CacheTypeStructureParser)
453 );
454 }
455
456 /**
457 This function parses the ACPI PPTT table.
458 When trace is enabled this function parses the PPTT table and
459 traces the ACPI table fields.
460
461 This function parses the following processor topology structures:
462 - Processor hierarchy node structure (Type 0)
463 - Cache Type Structure (Type 1)
464
465 This function also performs validation of the ACPI table fields.
466
467 @param [in] Trace If TRUE, trace the ACPI fields.
468 @param [in] Ptr Pointer to the start of the buffer.
469 @param [in] AcpiTableLength Length of the ACPI table.
470 @param [in] AcpiTableRevision Revision of the ACPI table.
471 **/
472 VOID
473 EFIAPI
474 ParseAcpiPptt (
475 IN BOOLEAN Trace,
476 IN UINT8 *Ptr,
477 IN UINT32 AcpiTableLength,
478 IN UINT8 AcpiTableRevision
479 )
480 {
481 UINT32 Offset;
482 UINT8 *ProcessorTopologyStructurePtr;
483
484 if (!Trace) {
485 return;
486 }
487
488 Offset = ParseAcpi (
489 TRUE,
490 0,
491 "PPTT",
492 Ptr,
493 AcpiTableLength,
494 PARSER_PARAMS (PpttParser)
495 );
496
497 ProcessorTopologyStructurePtr = Ptr + Offset;
498
499 while (Offset < AcpiTableLength) {
500 // Parse Processor Hierarchy Node Structure to obtain Type and Length.
501 ParseAcpi (
502 FALSE,
503 0,
504 NULL,
505 ProcessorTopologyStructurePtr,
506 AcpiTableLength - Offset,
507 PARSER_PARAMS (ProcessorTopologyStructureHeaderParser)
508 );
509
510 // Check if the values used to control the parsing logic have been
511 // successfully read.
512 if ((ProcessorTopologyStructureType == NULL) ||
513 (ProcessorTopologyStructureLength == NULL))
514 {
515 IncrementErrorCount ();
516 Print (
517 L"ERROR: Insufficient remaining table buffer length to read the " \
518 L"processor topology structure header. Length = %d.\n",
519 AcpiTableLength - Offset
520 );
521 return;
522 }
523
524 // Validate Processor Topology Structure length
525 if ((*ProcessorTopologyStructureLength == 0) ||
526 ((Offset + (*ProcessorTopologyStructureLength)) > AcpiTableLength))
527 {
528 IncrementErrorCount ();
529 Print (
530 L"ERROR: Invalid Processor Topology Structure length. " \
531 L"Length = %d. Offset = %d. AcpiTableLength = %d.\n",
532 *ProcessorTopologyStructureLength,
533 Offset,
534 AcpiTableLength
535 );
536 return;
537 }
538
539 PrintFieldName (2, L"* Structure Offset *");
540 Print (L"0x%x\n", Offset);
541
542 switch (*ProcessorTopologyStructureType) {
543 case EFI_ACPI_6_4_PPTT_TYPE_PROCESSOR:
544 DumpProcessorHierarchyNodeStructure (
545 ProcessorTopologyStructurePtr,
546 *ProcessorTopologyStructureLength
547 );
548 break;
549 case EFI_ACPI_6_4_PPTT_TYPE_CACHE:
550 DumpCacheTypeStructure (
551 ProcessorTopologyStructurePtr,
552 *ProcessorTopologyStructureLength
553 );
554 break;
555 case EFI_ACPI_6_3_PPTT_TYPE_ID:
556 IncrementErrorCount ();
557 Print (
558 L"ERROR: PPTT Type 2 - Processor ID has been removed and must not be"
559 L"used.\n"
560 );
561 break;
562 default:
563 IncrementErrorCount ();
564 Print (
565 L"ERROR: Unknown processor topology structure:"
566 L" Type = %d, Length = %d\n",
567 *ProcessorTopologyStructureType,
568 *ProcessorTopologyStructureLength
569 );
570 }
571
572 ProcessorTopologyStructurePtr += *ProcessorTopologyStructureLength;
573 Offset += *ProcessorTopologyStructureLength;
574 } // while
575 }