]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Hmat/HmatParser.c
ShellPkg/AcpiView: HMAT Parser
[mirror_edk2.git] / ShellPkg / Library / UefiShellAcpiViewCommandLib / Parsers / Hmat / HmatParser.c
1 /** @file
2 HMAT table parser
3
4 Copyright (c) 2020, Arm Limited.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 @par Reference(s):
8 - ACPI 6.3 Specification - January 2019
9
10 @par Glossary:
11 - MPDA - Memory Proximity Domain Attributes
12 - SLLBI - System Locality Latency and Bandwidth Information
13 - MSCI - Memory Side Cache Information
14 - Dom - Domain
15 **/
16
17 #include <Library/PrintLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/UefiLib.h>
20 #include "AcpiParser.h"
21 #include "AcpiView.h"
22
23 // Maximum Memory Domain matrix print size.
24 #define MAX_MEMORY_DOMAIN_TARGET_PRINT_MATRIX 10
25
26 // Local variables
27 STATIC CONST UINT16* HmatStructureType;
28 STATIC CONST UINT32* HmatStructureLength;
29
30 STATIC CONST UINT32* NumberInitiatorProximityDomain;
31 STATIC CONST UINT32* NumberTargetProximityDomain;
32 STATIC CONST
33 EFI_ACPI_6_3_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO_FLAGS*
34 SllbiFlags;
35
36 STATIC CONST UINT8* SllbiDataType;
37 STATIC CONST UINT16* NumberSMBIOSHandles;
38
39 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;
40
41 /**
42 Names of System Locality Latency Bandwidth Information (SLLBI) data types
43 **/
44 STATIC CONST CHAR16* SllbiNames[] = {
45 L"Access %sLatency%s",
46 L"Read %sLatency%s",
47 L"Write %sLatency%s",
48 L"Access %sBandwidth%s",
49 L"Read %sBandwidth%s",
50 L"Write %sBandwidth%s"
51 };
52
53 /**
54 This function validates the Cache Attributes field.
55
56 @param [in] Ptr Pointer to the start of the field data.
57 @param [in] Context Pointer to context specific information e.g. this
58 could be a pointer to the ACPI table header.
59 **/
60 STATIC
61 VOID
62 EFIAPI
63 ValidateCacheAttributes (
64 IN UINT8* Ptr,
65 IN VOID* Context
66 )
67 {
68 EFI_ACPI_6_3_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES*
69 Attributes;
70
71 Attributes =
72 (EFI_ACPI_6_3_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES*)Ptr;
73
74 if (Attributes->TotalCacheLevels > 0x3) {
75 IncrementErrorCount ();
76 Print (
77 L"\nERROR: Attributes bits [3:0] have invalid value: 0x%x",
78 Attributes->TotalCacheLevels
79 );
80 }
81 if (Attributes->CacheLevel > 0x3) {
82 IncrementErrorCount ();
83 Print (
84 L"\nERROR: Attributes bits [7:4] have invalid value: 0x%x",
85 Attributes->CacheLevel
86 );
87 }
88 if (Attributes->CacheAssociativity > 0x2) {
89 IncrementErrorCount ();
90 Print (
91 L"\nERROR: Attributes bits [11:8] have invalid value: 0x%x",
92 Attributes->CacheAssociativity
93 );
94 }
95 if (Attributes->WritePolicy > 0x2) {
96 IncrementErrorCount ();
97 Print (
98 L"\nERROR: Attributes bits [15:12] have invalid value: 0x%x",
99 Attributes->WritePolicy
100 );
101 }
102 }
103
104 /**
105 Dumps the cache attributes field
106
107 @param [in] Format Optional format string for tracing the data.
108 @param [in] Ptr Pointer to the start of the buffer.
109 **/
110 STATIC
111 VOID
112 EFIAPI
113 DumpCacheAttributes (
114 IN CONST CHAR16* Format OPTIONAL,
115 IN UINT8* Ptr
116 )
117 {
118 EFI_ACPI_6_3_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES*
119 Attributes;
120
121 Attributes =
122 (EFI_ACPI_6_3_HMAT_STRUCTURE_MEMORY_SIDE_CACHE_INFO_CACHE_ATTRIBUTES*)Ptr;
123
124 Print (L"\n");
125 PrintFieldName (4, L"Total Cache Levels");
126 Print (L"%d\n", Attributes->TotalCacheLevels);
127 PrintFieldName (4, L"Cache Level");
128 Print (L"%d\n", Attributes->CacheLevel);
129 PrintFieldName (4, L"Cache Associativity");
130 Print (L"%d\n", Attributes->CacheAssociativity);
131 PrintFieldName (4, L"Write Policy");
132 Print (L"%d\n", Attributes->WritePolicy);
133 PrintFieldName (4, L"Cache Line Size");
134 Print (L"%d\n", Attributes->CacheLineSize);
135 }
136
137 /**
138 An ACPI_PARSER array describing the ACPI HMAT Table.
139 */
140 STATIC CONST ACPI_PARSER HmatParser[] = {
141 PARSE_ACPI_HEADER (&AcpiHdrInfo),
142 {L"Reserved", 4, 36, NULL, NULL, NULL, NULL, NULL}
143 };
144
145 /**
146 An ACPI_PARSER array describing the HMAT structure header.
147 */
148 STATIC CONST ACPI_PARSER HmatStructureHeaderParser[] = {
149 {L"Type", 2, 0, NULL, NULL, (VOID**)&HmatStructureType, NULL, NULL},
150 {L"Reserved", 2, 2, NULL, NULL, NULL, NULL, NULL},
151 {L"Length", 4, 4, NULL, NULL, (VOID**)&HmatStructureLength, NULL, NULL}
152 };
153
154 /**
155 An ACPI PARSER array describing the Memory Proximity Domain Attributes
156 Structure - Type 0.
157 */
158 STATIC CONST ACPI_PARSER MemProximityDomainAttributeParser[] = {
159 {L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL},
160 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},
161 {L"Length", 4, 4, L"%d", NULL, NULL, NULL, NULL},
162 {L"Flags", 2, 8, L"0x%x", NULL, NULL, NULL, NULL},
163 {L"Reserved", 2, 10, L"0x%x", NULL, NULL, NULL, NULL},
164 {L"Proximity Dom for initiator", 4, 12, L"0x%x", NULL, NULL, NULL, NULL},
165 {L"Proximity Dom for memory", 4, 16, L"0x%x", NULL, NULL, NULL, NULL},
166 {L"Reserved", 4, 20, L"0x%x", NULL, NULL, NULL, NULL},
167 {L"Reserved", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL},
168 {L"Reserved", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL}
169 };
170
171 /**
172 An ACPI PARSER array describing the System Locality Latency and Bandwidth
173 Information Structure - Type 1.
174 */
175 STATIC CONST ACPI_PARSER SllbiParser[] = {
176 {L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL},
177 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},
178 {L"Length", 4, 4, L"%d", NULL, NULL, NULL, NULL},
179 {L"Flags", 1, 8, L"0x%x", NULL, (VOID**)&SllbiFlags, NULL, NULL},
180 {L"Data type", 1, 9, L"0x%x", NULL, (VOID**)&SllbiDataType, NULL, NULL},
181 {L"Reserved", 2, 10, L"0x%x", NULL, NULL, NULL, NULL},
182 {L"Initiator Proximity Dom Count", 4, 12, L"%d", NULL,
183 (VOID**)&NumberInitiatorProximityDomain, NULL, NULL},
184 {L"Target Proximity Dom Count", 4, 16, L"%d", NULL,
185 (VOID**)&NumberTargetProximityDomain, NULL, NULL},
186 {L"Reserved", 4, 20, L"0x%x", NULL, NULL, NULL, NULL},
187 {L"Entry Base Unit", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL}
188 // initiator Proximity Domain list ...
189 // target Proximity Domain list ...
190 // Latency/Bandwidth matrix ...
191 };
192
193 /**
194 An ACPI PARSER array describing the Memory Side Cache Information
195 Structure - Type 2.
196 */
197 STATIC CONST ACPI_PARSER MemSideCacheInfoParser[] = {
198 {L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL},
199 {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},
200 {L"Length", 4, 4, L"%d", NULL, NULL, NULL, NULL},
201 {L"Proximity Dom for memory", 4, 8, L"0x%x", NULL, NULL, NULL, NULL},
202 {L"Reserved", 4, 12, L"0x%x", NULL, NULL, NULL, NULL},
203 {L"Memory Side Cache Size", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL},
204 {L"Cache Attributes", 4, 24, NULL, DumpCacheAttributes, NULL,
205 ValidateCacheAttributes, NULL},
206 {L"Reserved", 2, 28, L"0x%x", NULL, NULL, NULL, NULL},
207 {L"SMBIOS Handle Count", 2, 30, L"%d", NULL,
208 (VOID**)&NumberSMBIOSHandles, NULL, NULL}
209 // SMBIOS handles List ...
210 };
211
212 /**
213 This function parses the Memory Proximity Domain Attributes
214 Structure (Type 0).
215
216 @param [in] Ptr Pointer to the start of the Memory Proximity Domain
217 Attributes Structure data.
218 @param [in] Length Length of the Memory Proximity Domain Attributes
219 Structure.
220 **/
221 STATIC
222 VOID
223 DumpMpda (
224 IN UINT8* Ptr,
225 IN UINT32 Length
226 )
227 {
228 ParseAcpi (
229 TRUE,
230 2,
231 "Memory Proximity Domain Attributes Structure",
232 Ptr,
233 Length,
234 PARSER_PARAMS (MemProximityDomainAttributeParser)
235 );
236 }
237
238 /**
239 This function parses the System Locality Latency and Bandwidth Information
240 Structure (Type 1).
241
242 @param [in] Ptr Pointer to the start of the System Locality Latency and
243 Bandwidth Information Structure data.
244 @param [in] Length Length of the System Locality Latency and Bandwidth
245 Information Structure.
246 **/
247 STATIC
248 VOID
249 DumpSllbi (
250 IN UINT8* Ptr,
251 IN UINT32 Length
252 )
253 {
254 CONST UINT32* InitiatorProximityDomainList;
255 CONST UINT32* TargetProximityDomainList;
256 CONST UINT16* LatencyBandwidthMatrix;
257 UINT32 Offset;
258 CHAR16 Buffer[OUTPUT_FIELD_COLUMN_WIDTH];
259 CHAR16 SecondBuffer[OUTPUT_FIELD_COLUMN_WIDTH];
260 UINT32 RequiredTableSize;
261 UINT32 Index;
262 UINT32 IndexInitiator;
263 UINT32 IndexTarget;
264 UINT32 TargetStartOffset;
265
266 Offset = ParseAcpi (
267 TRUE,
268 2,
269 "System Locality Latency and Bandwidth Information Structure",
270 Ptr,
271 Length,
272 PARSER_PARAMS (SllbiParser)
273 );
274
275 // Check if the values used to control the parsing logic have been
276 // successfully read.
277 if ((SllbiFlags == NULL) ||
278 (SllbiDataType == NULL) ||
279 (NumberInitiatorProximityDomain == NULL) ||
280 (NumberTargetProximityDomain == NULL)) {
281 IncrementErrorCount ();
282 Print (
283 L"ERROR: Insufficient remaining table buffer length to read the " \
284 L"SLLBI structure header. Length = %d.\n",
285 Length
286 );
287 return;
288 }
289
290 RequiredTableSize = (*NumberInitiatorProximityDomain * sizeof (UINT32)) +
291 (*NumberTargetProximityDomain * sizeof (UINT32)) +
292 (*NumberInitiatorProximityDomain *
293 *NumberTargetProximityDomain * sizeof (UINT16)) +
294 Offset;
295
296 if (RequiredTableSize > Length) {
297 IncrementErrorCount ();
298 Print (
299 L"ERROR: Insufficient System Locality Latency and Bandwidth" \
300 L"Information Structure length. TableLength = %d. " \
301 L"RequiredTableLength = %d.\n",
302 Length,
303 RequiredTableSize
304 );
305 return;
306 }
307
308 InitiatorProximityDomainList = (UINT32*) (Ptr + Offset);
309 TargetProximityDomainList = InitiatorProximityDomainList +
310 *NumberInitiatorProximityDomain;
311 LatencyBandwidthMatrix = (UINT16*) (TargetProximityDomainList +
312 *NumberTargetProximityDomain);
313
314 // Display each element of the Initiator Proximity Domain list
315 for (Index = 0; Index < *NumberInitiatorProximityDomain; Index++) {
316 UnicodeSPrint (
317 Buffer,
318 sizeof (Buffer),
319 L"Initiator Proximity Dom [%d]",
320 Index
321 );
322
323 PrintFieldName (4, Buffer);
324 Print (
325 L"0x%x\n",
326 InitiatorProximityDomainList[Index]
327 );
328 }
329
330 // Display each element of the Target Proximity Domain list
331 for (Index = 0; Index < *NumberTargetProximityDomain; Index++) {
332 UnicodeSPrint (
333 Buffer,
334 sizeof (Buffer),
335 L"Target Proximity Dom [%d]",
336 Index
337 );
338
339 PrintFieldName (4, Buffer);
340 Print (
341 L"0x%x\n",
342 TargetProximityDomainList[Index]
343 );
344 }
345
346 // Create base name depending on Data Type in this Structure
347 if (*SllbiDataType >= ARRAY_SIZE (SllbiNames)) {
348 IncrementErrorCount ();
349 Print (L"Error: Unkown Data Type. DataType = 0x%x.\n", *SllbiDataType);
350 return;
351 }
352 StrCpyS (Buffer, sizeof (Buffer), SllbiNames[*SllbiDataType]);
353
354 // Adjust base name depending on Memory Hierarchy in this Structure
355 switch (SllbiFlags->MemoryHierarchy) {
356 case 0:
357 UnicodeSPrint (
358 SecondBuffer,
359 sizeof (SecondBuffer),
360 Buffer,
361 L"",
362 L"%s"
363 );
364 break;
365 case 1:
366 case 2:
367 case 3:
368 UnicodeSPrint (
369 SecondBuffer,
370 sizeof (SecondBuffer),
371 Buffer,
372 L"Hit ",
373 L"%s"
374 );
375 break;
376 default:
377 IncrementErrorCount ();
378 Print (
379 L"Error: Invalid Memory Hierarchy. MemoryHierarchy = %d.\n",
380 SllbiFlags->MemoryHierarchy
381 );
382 return;
383
384 } // switch
385
386 if (*NumberTargetProximityDomain <= MAX_MEMORY_DOMAIN_TARGET_PRINT_MATRIX) {
387 // Display the latency/bandwidth matrix as a matrix
388 UnicodeSPrint (
389 Buffer,
390 sizeof (Buffer),
391 SecondBuffer,
392 L""
393 );
394 PrintFieldName (4, Buffer);
395
396 Print (L"\n Target : X-axis (Horizontal)");
397 Print (L"\n Initiator : Y-axis (Vertical)");
398 Print (L"\n |");
399
400 for (IndexTarget = 0;
401 IndexTarget < *NumberTargetProximityDomain;
402 IndexTarget++) {
403 Print (L" %2d", IndexTarget);
404 }
405
406 Print (L"\n ---+");
407 for (IndexTarget = 0;
408 IndexTarget < *NumberTargetProximityDomain;
409 IndexTarget++) {
410 Print (L"------");
411 }
412 Print (L"\n");
413
414 TargetStartOffset = 0;
415 for (IndexInitiator = 0;
416 IndexInitiator < *NumberInitiatorProximityDomain;
417 IndexInitiator++) {
418 Print (L" %2d |", IndexInitiator);
419 for (IndexTarget = 0;
420 IndexTarget < *NumberTargetProximityDomain;
421 IndexTarget++) {
422 Print (
423 L" %5d",
424 LatencyBandwidthMatrix[TargetStartOffset + IndexTarget]
425 );
426 } // for Target
427 Print (L"\n");
428 TargetStartOffset += (*NumberTargetProximityDomain);
429 } // for Initiator
430 Print (L"\n");
431 } else {
432 // Display the latency/bandwidth matrix as a list
433 UnicodeSPrint (
434 Buffer,
435 sizeof (Buffer),
436 SecondBuffer,
437 L" [%d][%d]"
438 );
439
440 TargetStartOffset = 0;
441 for (IndexInitiator = 0;
442 IndexInitiator < *NumberInitiatorProximityDomain;
443 IndexInitiator++) {
444 for (IndexTarget = 0;
445 IndexTarget < *NumberTargetProximityDomain;
446 IndexTarget++) {
447 UnicodeSPrint (
448 SecondBuffer,
449 sizeof (SecondBuffer),
450 Buffer,
451 IndexInitiator,
452 IndexTarget
453 );
454
455 PrintFieldName (4, SecondBuffer);
456 Print (
457 L"%d\n",
458 LatencyBandwidthMatrix[TargetStartOffset + IndexTarget]
459 );
460 } // for Target
461 TargetStartOffset += (*NumberTargetProximityDomain);
462 } // for Initiator
463 }
464 }
465
466 /**
467 This function parses the Memory Side Cache Information Structure (Type 2).
468
469 @param [in] Ptr Pointer to the start of the Memory Side Cache Information
470 Structure data.
471 @param [in] Length Length of the Memory Side Cache Information Structure.
472 **/
473 STATIC
474 VOID
475 DumpMsci (
476 IN UINT8* Ptr,
477 IN UINT32 Length
478 )
479 {
480 CONST UINT16* SMBIOSHandlesList;
481 CHAR16 Buffer[OUTPUT_FIELD_COLUMN_WIDTH];
482 UINT32 Offset;
483 UINT16 Index;
484
485 Offset = ParseAcpi (
486 TRUE,
487 2,
488 "Memory Side Cache Information Structure",
489 Ptr,
490 Length,
491 PARSER_PARAMS (MemSideCacheInfoParser)
492 );
493
494 // Check if the values used to control the parsing logic have been
495 // successfully read.
496 if (NumberSMBIOSHandles == NULL) {
497 IncrementErrorCount ();
498 Print (
499 L"ERROR: Insufficient remaining table buffer length to read the " \
500 L"MSCI structure header. Length = %d.\n",
501 Length
502 );
503 return;
504 }
505
506 if ((*NumberSMBIOSHandles * sizeof (UINT16)) > (Length - Offset)) {
507 IncrementErrorCount ();
508 Print (
509 L"ERROR: Invalid Number of SMBIOS Handles. SMBIOSHandlesCount = %d." \
510 L"RemainingBufferLength = %d.\n",
511 *NumberSMBIOSHandles,
512 Length - Offset
513 );
514 return;
515 }
516
517 SMBIOSHandlesList = (UINT16*) (Ptr + Offset);
518
519 for (Index = 0; Index < *NumberSMBIOSHandles; Index++) {
520 UnicodeSPrint (
521 Buffer,
522 sizeof (Buffer),
523 L"SMBIOS Handles [%d]",
524 Index
525 );
526
527 PrintFieldName (4, Buffer);
528 Print (
529 L"0x%x\n",
530 SMBIOSHandlesList[Index]
531 );
532 }
533 }
534
535 /**
536 This function parses the ACPI HMAT table.
537 When trace is enabled this function parses the HMAT table and
538 traces the ACPI table fields.
539
540 This function parses the following HMAT structures:
541 - Memory Proximity Domain Attributes Structure (Type 0)
542 - System Locality Latency and Bandwidth Info Structure (Type 1)
543 - Memory Side Cache Info structure (Type 2)
544
545 This function also performs validation of the ACPI table fields.
546
547 @param [in] Trace If TRUE, trace the ACPI fields.
548 @param [in] Ptr Pointer to the start of the buffer.
549 @param [in] AcpiTableLength Length of the ACPI table.
550 @param [in] AcpiTableRevision Revision of the ACPI table.
551 **/
552 VOID
553 EFIAPI
554 ParseAcpiHmat (
555 IN BOOLEAN Trace,
556 IN UINT8* Ptr,
557 IN UINT32 AcpiTableLength,
558 IN UINT8 AcpiTableRevision
559 )
560 {
561 UINT32 Offset;
562 UINT8* HmatStructurePtr;
563
564 if (!Trace) {
565 return;
566 }
567
568 Offset = ParseAcpi (
569 Trace,
570 0,
571 "HMAT",
572 Ptr,
573 AcpiTableLength,
574 PARSER_PARAMS (HmatParser)
575 );
576
577 HmatStructurePtr = Ptr + Offset;
578
579 while (Offset < AcpiTableLength) {
580 // Parse HMAT Structure Header to obtain Type and Length.
581 ParseAcpi (
582 FALSE,
583 0,
584 NULL,
585 HmatStructurePtr,
586 AcpiTableLength - Offset,
587 PARSER_PARAMS (HmatStructureHeaderParser)
588 );
589
590 // Check if the values used to control the parsing logic have been
591 // successfully read.
592 if ((HmatStructureType == NULL) ||
593 (HmatStructureLength == NULL)) {
594 IncrementErrorCount ();
595 Print (
596 L"ERROR: Insufficient remaining table buffer length to read the " \
597 L"HMAT structure header. Length = %d.\n",
598 AcpiTableLength - Offset
599 );
600 return;
601 }
602
603 // Validate HMAT Structure length.
604 if ((*HmatStructureLength == 0) ||
605 ((Offset + (*HmatStructureLength)) > AcpiTableLength)) {
606 IncrementErrorCount ();
607 Print (
608 L"ERROR: Invalid HMAT Structure length. " \
609 L"Length = %d. Offset = %d. AcpiTableLength = %d.\n",
610 *HmatStructureLength,
611 Offset,
612 AcpiTableLength
613 );
614 return;
615 }
616
617 switch (*HmatStructureType) {
618 case EFI_ACPI_6_3_HMAT_TYPE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES:
619 DumpMpda (
620 HmatStructurePtr,
621 *HmatStructureLength
622 );
623 break;
624 case EFI_ACPI_6_3_HMAT_TYPE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO:
625 DumpSllbi (
626 HmatStructurePtr,
627 *HmatStructureLength
628 );
629 break;
630 case EFI_ACPI_6_3_HMAT_TYPE_MEMORY_SIDE_CACHE_INFO:
631 DumpMsci (
632 HmatStructurePtr,
633 *HmatStructureLength
634 );
635 break;
636 default:
637 IncrementErrorCount ();
638 Print (
639 L"ERROR: Unknown HMAT structure:"
640 L" Type = %d, Length = %d\n",
641 *HmatStructureType,
642 *HmatStructureLength
643 );
644 break;
645 } // switch
646
647 HmatStructurePtr += *HmatStructureLength;
648 Offset += *HmatStructureLength;
649 } // while
650 }