]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c
3f12a33050a4e4ab3be2187c90ef8dcf0882283d
[mirror_edk2.git] / ShellPkg / Library / UefiShellAcpiViewCommandLib / AcpiParser.c
1 /** @file
2 ACPI parser
3
4 Copyright (c) 2016 - 2020, ARM Limited. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 **/
7
8 #include <Uefi.h>
9 #include <Library/UefiLib.h>
10 #include <Library/UefiBootServicesTableLib.h>
11 #include "AcpiParser.h"
12 #include "AcpiView.h"
13
14 STATIC UINT32 gIndent;
15 STATIC UINT32 mTableErrorCount;
16 STATIC UINT32 mTableWarningCount;
17
18 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;
19
20 /**
21 An ACPI_PARSER array describing the ACPI header.
22 **/
23 STATIC CONST ACPI_PARSER AcpiHeaderParser[] = {
24 PARSE_ACPI_HEADER (&AcpiHdrInfo)
25 };
26
27 /**
28 This function resets the ACPI table error counter to Zero.
29 **/
30 VOID
31 ResetErrorCount (
32 VOID
33 )
34 {
35 mTableErrorCount = 0;
36 }
37
38 /**
39 This function returns the ACPI table error count.
40
41 @retval Returns the count of errors detected in the ACPI tables.
42 **/
43 UINT32
44 GetErrorCount (
45 VOID
46 )
47 {
48 return mTableErrorCount;
49 }
50
51 /**
52 This function resets the ACPI table warning counter to Zero.
53 **/
54 VOID
55 ResetWarningCount (
56 VOID
57 )
58 {
59 mTableWarningCount = 0;
60 }
61
62 /**
63 This function returns the ACPI table warning count.
64
65 @retval Returns the count of warning detected in the ACPI tables.
66 **/
67 UINT32
68 GetWarningCount (
69 VOID
70 )
71 {
72 return mTableWarningCount;
73 }
74
75 /**
76 This function increments the ACPI table error counter.
77 **/
78 VOID
79 EFIAPI
80 IncrementErrorCount (
81 VOID
82 )
83 {
84 mTableErrorCount++;
85 }
86
87 /**
88 This function increments the ACPI table warning counter.
89 **/
90 VOID
91 EFIAPI
92 IncrementWarningCount (
93 VOID
94 )
95 {
96 mTableWarningCount++;
97 }
98
99 /**
100 This function verifies the ACPI table checksum.
101
102 This function verifies the checksum for the ACPI table and optionally
103 prints the status.
104
105 @param [in] Log If TRUE log the status of the checksum.
106 @param [in] Ptr Pointer to the start of the table buffer.
107 @param [in] Length The length of the buffer.
108
109 @retval TRUE The checksum is OK.
110 @retval FALSE The checksum failed.
111 **/
112 BOOLEAN
113 EFIAPI
114 VerifyChecksum (
115 IN BOOLEAN Log,
116 IN UINT8* Ptr,
117 IN UINT32 Length
118 )
119 {
120 UINTN ByteCount;
121 UINT8 Checksum;
122 UINTN OriginalAttribute;
123
124 //
125 // set local variables to suppress incorrect compiler/analyzer warnings
126 //
127 OriginalAttribute = 0;
128 ByteCount = 0;
129 Checksum = 0;
130
131 while (ByteCount < Length) {
132 Checksum += *(Ptr++);
133 ByteCount++;
134 }
135
136 if (Log) {
137 OriginalAttribute = gST->ConOut->Mode->Attribute;
138 if (Checksum == 0) {
139 if (GetColourHighlighting ()) {
140 gST->ConOut->SetAttribute (
141 gST->ConOut,
142 EFI_TEXT_ATTR (EFI_GREEN,
143 ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))
144 );
145 }
146 Print (L"Table Checksum : OK\n\n");
147 } else {
148 IncrementErrorCount ();
149 if (GetColourHighlighting ()) {
150 gST->ConOut->SetAttribute (
151 gST->ConOut,
152 EFI_TEXT_ATTR (EFI_RED,
153 ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))
154 );
155 }
156 Print (L"Table Checksum : FAILED (0x%X)\n\n", Checksum);
157 }
158 if (GetColourHighlighting ()) {
159 gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute);
160 }
161 }
162
163 return (Checksum == 0);
164 }
165
166 /**
167 This function performs a raw data dump of the ACPI table.
168
169 @param [in] Ptr Pointer to the start of the table buffer.
170 @param [in] Length The length of the buffer.
171 **/
172 VOID
173 EFIAPI
174 DumpRaw (
175 IN UINT8* Ptr,
176 IN UINT32 Length
177 )
178 {
179 UINTN ByteCount;
180 UINTN PartLineChars;
181 UINTN AsciiBufferIndex;
182 CHAR8 AsciiBuffer[17];
183
184 ByteCount = 0;
185 AsciiBufferIndex = 0;
186
187 Print (L"Address : 0x%p\n", Ptr);
188 Print (L"Length : %d\n", Length);
189
190 while (ByteCount < Length) {
191 if ((ByteCount & 0x0F) == 0) {
192 AsciiBuffer[AsciiBufferIndex] = '\0';
193 Print (L" %a\n%08X : ", AsciiBuffer, ByteCount);
194 AsciiBufferIndex = 0;
195 } else if ((ByteCount & 0x07) == 0) {
196 Print (L"- ");
197 }
198
199 if ((*Ptr >= ' ') && (*Ptr < 0x7F)) {
200 AsciiBuffer[AsciiBufferIndex++] = *Ptr;
201 } else {
202 AsciiBuffer[AsciiBufferIndex++] = '.';
203 }
204
205 Print (L"%02X ", *Ptr++);
206
207 ByteCount++;
208 }
209
210 // Justify the final line using spaces before printing
211 // the ASCII data.
212 PartLineChars = (Length & 0x0F);
213 if (PartLineChars != 0) {
214 PartLineChars = 48 - (PartLineChars * 3);
215 if ((Length & 0x0F) <= 8) {
216 PartLineChars += 2;
217 }
218 while (PartLineChars > 0) {
219 Print (L" ");
220 PartLineChars--;
221 }
222 }
223
224 // Print ASCII data for the final line.
225 AsciiBuffer[AsciiBufferIndex] = '\0';
226 Print (L" %a\n\n", AsciiBuffer);
227 }
228
229 /**
230 This function traces 1 byte of data as specified in the format string.
231
232 @param [in] Format The format string for tracing the data.
233 @param [in] Ptr Pointer to the start of the buffer.
234 **/
235 VOID
236 EFIAPI
237 DumpUint8 (
238 IN CONST CHAR16* Format,
239 IN UINT8* Ptr
240 )
241 {
242 Print (Format, *Ptr);
243 }
244
245 /**
246 This function traces 2 bytes of data as specified in the format string.
247
248 @param [in] Format The format string for tracing the data.
249 @param [in] Ptr Pointer to the start of the buffer.
250 **/
251 VOID
252 EFIAPI
253 DumpUint16 (
254 IN CONST CHAR16* Format,
255 IN UINT8* Ptr
256 )
257 {
258 Print (Format, *(UINT16*)Ptr);
259 }
260
261 /**
262 This function traces 4 bytes of data as specified in the format string.
263
264 @param [in] Format The format string for tracing the data.
265 @param [in] Ptr Pointer to the start of the buffer.
266 **/
267 VOID
268 EFIAPI
269 DumpUint32 (
270 IN CONST CHAR16* Format,
271 IN UINT8* Ptr
272 )
273 {
274 Print (Format, *(UINT32*)Ptr);
275 }
276
277 /**
278 This function traces 8 bytes of data as specified by the format string.
279
280 @param [in] Format The format string for tracing the data.
281 @param [in] Ptr Pointer to the start of the buffer.
282 **/
283 VOID
284 EFIAPI
285 DumpUint64 (
286 IN CONST CHAR16* Format,
287 IN UINT8* Ptr
288 )
289 {
290 // Some fields are not aligned and this causes alignment faults
291 // on ARM platforms if the compiler generates LDRD instructions.
292 // Perform word access so that LDRD instructions are not generated.
293 UINT64 Val;
294
295 Val = *(UINT32*)(Ptr + sizeof (UINT32));
296
297 Val = LShiftU64(Val,32);
298 Val |= (UINT64)*(UINT32*)Ptr;
299
300 Print (Format, Val);
301 }
302
303 /**
304 This function traces 3 characters which can be optionally
305 formated using the format string if specified.
306
307 If no format string is specified the Format must be NULL.
308
309 @param [in] Format Optional format string for tracing the data.
310 @param [in] Ptr Pointer to the start of the buffer.
311 **/
312 VOID
313 EFIAPI
314 Dump3Chars (
315 IN CONST CHAR16* Format OPTIONAL,
316 IN UINT8* Ptr
317 )
318 {
319 Print (
320 (Format != NULL) ? Format : L"%c%c%c",
321 Ptr[0],
322 Ptr[1],
323 Ptr[2]
324 );
325 }
326
327 /**
328 This function traces 4 characters which can be optionally
329 formated using the format string if specified.
330
331 If no format string is specified the Format must be NULL.
332
333 @param [in] Format Optional format string for tracing the data.
334 @param [in] Ptr Pointer to the start of the buffer.
335 **/
336 VOID
337 EFIAPI
338 Dump4Chars (
339 IN CONST CHAR16* Format OPTIONAL,
340 IN UINT8* Ptr
341 )
342 {
343 Print (
344 (Format != NULL) ? Format : L"%c%c%c%c",
345 Ptr[0],
346 Ptr[1],
347 Ptr[2],
348 Ptr[3]
349 );
350 }
351
352 /**
353 This function traces 6 characters which can be optionally
354 formated using the format string if specified.
355
356 If no format string is specified the Format must be NULL.
357
358 @param [in] Format Optional format string for tracing the data.
359 @param [in] Ptr Pointer to the start of the buffer.
360 **/
361 VOID
362 EFIAPI
363 Dump6Chars (
364 IN CONST CHAR16* Format OPTIONAL,
365 IN UINT8* Ptr
366 )
367 {
368 Print (
369 (Format != NULL) ? Format : L"%c%c%c%c%c%c",
370 Ptr[0],
371 Ptr[1],
372 Ptr[2],
373 Ptr[3],
374 Ptr[4],
375 Ptr[5]
376 );
377 }
378
379 /**
380 This function traces 8 characters which can be optionally
381 formated using the format string if specified.
382
383 If no format string is specified the Format must be NULL.
384
385 @param [in] Format Optional format string for tracing the data.
386 @param [in] Ptr Pointer to the start of the buffer.
387 **/
388 VOID
389 EFIAPI
390 Dump8Chars (
391 IN CONST CHAR16* Format OPTIONAL,
392 IN UINT8* Ptr
393 )
394 {
395 Print (
396 (Format != NULL) ? Format : L"%c%c%c%c%c%c%c%c",
397 Ptr[0],
398 Ptr[1],
399 Ptr[2],
400 Ptr[3],
401 Ptr[4],
402 Ptr[5],
403 Ptr[6],
404 Ptr[7]
405 );
406 }
407
408 /**
409 This function traces 12 characters which can be optionally
410 formated using the format string if specified.
411
412 If no format string is specified the Format must be NULL.
413
414 @param [in] Format Optional format string for tracing the data.
415 @param [in] Ptr Pointer to the start of the buffer.
416 **/
417 VOID
418 EFIAPI
419 Dump12Chars (
420 IN CONST CHAR16* Format OPTIONAL,
421 IN UINT8* Ptr
422 )
423 {
424 Print (
425 (Format != NULL) ? Format : L"%c%c%c%c%c%c%c%c%c%c%c%c",
426 Ptr[0],
427 Ptr[1],
428 Ptr[2],
429 Ptr[3],
430 Ptr[4],
431 Ptr[5],
432 Ptr[6],
433 Ptr[7],
434 Ptr[8],
435 Ptr[9],
436 Ptr[10],
437 Ptr[11]
438 );
439 }
440
441 /**
442 This function indents and prints the ACPI table Field Name.
443
444 @param [in] Indent Number of spaces to add to the global table indent.
445 The global table indent is 0 by default; however
446 this value is updated on entry to the ParseAcpi()
447 by adding the indent value provided to ParseAcpi()
448 and restored back on exit.
449 Therefore the total indent in the output is
450 dependent on from where this function is called.
451 @param [in] FieldName Pointer to the Field Name.
452 **/
453 VOID
454 EFIAPI
455 PrintFieldName (
456 IN UINT32 Indent,
457 IN CONST CHAR16* FieldName
458 )
459 {
460 Print (
461 L"%*a%-*s : ",
462 gIndent + Indent,
463 "",
464 (OUTPUT_FIELD_COLUMN_WIDTH - gIndent - Indent),
465 FieldName
466 );
467 }
468
469 /**
470 This function is used to parse an ACPI table buffer.
471
472 The ACPI table buffer is parsed using the ACPI table parser information
473 specified by a pointer to an array of ACPI_PARSER elements. This parser
474 function iterates through each item on the ACPI_PARSER array and logs the
475 ACPI table fields.
476
477 This function can optionally be used to parse ACPI tables and fetch specific
478 field values. The ItemPtr member of the ACPI_PARSER structure (where used)
479 is updated by this parser function to point to the selected field data
480 (e.g. useful for variable length nested fields).
481
482 @param [in] Trace Trace the ACPI fields TRUE else only parse the
483 table.
484 @param [in] Indent Number of spaces to indent the output.
485 @param [in] AsciiName Optional pointer to an ASCII string that describes
486 the table being parsed.
487 @param [in] Ptr Pointer to the start of the buffer.
488 @param [in] Length Length of the buffer pointed by Ptr.
489 @param [in] Parser Pointer to an array of ACPI_PARSER structure that
490 describes the table being parsed.
491 @param [in] ParserItems Number of items in the ACPI_PARSER array.
492
493 @retval Number of bytes parsed.
494 **/
495 UINT32
496 EFIAPI
497 ParseAcpi (
498 IN BOOLEAN Trace,
499 IN UINT32 Indent,
500 IN CONST CHAR8* AsciiName OPTIONAL,
501 IN UINT8* Ptr,
502 IN UINT32 Length,
503 IN CONST ACPI_PARSER* Parser,
504 IN UINT32 ParserItems
505 )
506 {
507 UINT32 Index;
508 UINT32 Offset;
509 BOOLEAN HighLight;
510 UINTN OriginalAttribute;
511
512 //
513 // set local variables to suppress incorrect compiler/analyzer warnings
514 //
515 OriginalAttribute = 0;
516 Offset = 0;
517
518 // Increment the Indent
519 gIndent += Indent;
520
521 if (Trace && (AsciiName != NULL)){
522 HighLight = GetColourHighlighting ();
523
524 if (HighLight) {
525 OriginalAttribute = gST->ConOut->Mode->Attribute;
526 gST->ConOut->SetAttribute (
527 gST->ConOut,
528 EFI_TEXT_ATTR(EFI_YELLOW,
529 ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))
530 );
531 }
532 Print (
533 L"%*a%-*a :\n",
534 gIndent,
535 "",
536 (OUTPUT_FIELD_COLUMN_WIDTH - gIndent),
537 AsciiName
538 );
539 if (HighLight) {
540 gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute);
541 }
542 }
543
544 for (Index = 0; Index < ParserItems; Index++) {
545 if ((Offset + Parser[Index].Length) > Length) {
546
547 // For fields outside the buffer length provided, reset any pointers
548 // which were supposed to be updated by this function call
549 if (Parser[Index].ItemPtr != NULL) {
550 *Parser[Index].ItemPtr = NULL;
551 }
552
553 // We don't parse past the end of the max length specified
554 continue;
555 }
556
557 if (GetConsistencyChecking () &&
558 (Offset != Parser[Index].Offset)) {
559 IncrementErrorCount ();
560 Print (
561 L"\nERROR: %a: Offset Mismatch for %s\n"
562 L"CurrentOffset = %d FieldOffset = %d\n",
563 AsciiName,
564 Parser[Index].NameStr,
565 Offset,
566 Parser[Index].Offset
567 );
568 }
569
570 if (Trace) {
571 // if there is a Formatter function let the function handle
572 // the printing else if a Format is specified in the table use
573 // the Format for printing
574 PrintFieldName (2, Parser[Index].NameStr);
575 if (Parser[Index].PrintFormatter != NULL) {
576 Parser[Index].PrintFormatter (Parser[Index].Format, Ptr);
577 } else if (Parser[Index].Format != NULL) {
578 switch (Parser[Index].Length) {
579 case 1:
580 DumpUint8 (Parser[Index].Format, Ptr);
581 break;
582 case 2:
583 DumpUint16 (Parser[Index].Format, Ptr);
584 break;
585 case 4:
586 DumpUint32 (Parser[Index].Format, Ptr);
587 break;
588 case 8:
589 DumpUint64 (Parser[Index].Format, Ptr);
590 break;
591 default:
592 Print (
593 L"\nERROR: %a: CANNOT PARSE THIS FIELD, Field Length = %d\n",
594 AsciiName,
595 Parser[Index].Length
596 );
597 } // switch
598
599 // Validating only makes sense if we are tracing
600 // the parsed table entries, to report by table name.
601 if (GetConsistencyChecking () &&
602 (Parser[Index].FieldValidator != NULL)) {
603 Parser[Index].FieldValidator (Ptr, Parser[Index].Context);
604 }
605 }
606 Print (L"\n");
607 } // if (Trace)
608
609 if (Parser[Index].ItemPtr != NULL) {
610 *Parser[Index].ItemPtr = (VOID*)Ptr;
611 }
612
613 Ptr += Parser[Index].Length;
614 Offset += Parser[Index].Length;
615 } // for
616
617 // Decrement the Indent
618 gIndent -= Indent;
619 return Offset;
620 }
621
622 /**
623 An array describing the ACPI Generic Address Structure.
624 The GasParser array is used by the ParseAcpi function to parse and/or trace
625 the GAS structure.
626 **/
627 STATIC CONST ACPI_PARSER GasParser[] = {
628 {L"Address Space ID", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},
629 {L"Register Bit Width", 1, 1, L"0x%x", NULL, NULL, NULL, NULL},
630 {L"Register Bit Offset", 1, 2, L"0x%x", NULL, NULL, NULL, NULL},
631 {L"Address Size", 1, 3, L"0x%x", NULL, NULL, NULL, NULL},
632 {L"Address", 8, 4, L"0x%lx", NULL, NULL, NULL, NULL}
633 };
634
635 /**
636 This function indents and traces the GAS structure as described by the GasParser.
637
638 @param [in] Ptr Pointer to the start of the buffer.
639 @param [in] Indent Number of spaces to indent the output.
640 @param [in] Length Length of the GAS structure buffer.
641
642 @retval Number of bytes parsed.
643 **/
644 UINT32
645 EFIAPI
646 DumpGasStruct (
647 IN UINT8* Ptr,
648 IN UINT32 Indent,
649 IN UINT32 Length
650 )
651 {
652 Print (L"\n");
653 return ParseAcpi (
654 TRUE,
655 Indent,
656 NULL,
657 Ptr,
658 Length,
659 PARSER_PARAMS (GasParser)
660 );
661 }
662
663 /**
664 This function traces the GAS structure as described by the GasParser.
665
666 @param [in] Format Optional format string for tracing the data.
667 @param [in] Ptr Pointer to the start of the buffer.
668 **/
669 VOID
670 EFIAPI
671 DumpGas (
672 IN CONST CHAR16* Format OPTIONAL,
673 IN UINT8* Ptr
674 )
675 {
676 DumpGasStruct (Ptr, 2, sizeof (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE));
677 }
678
679 /**
680 This function traces the ACPI header as described by the AcpiHeaderParser.
681
682 @param [in] Ptr Pointer to the start of the buffer.
683
684 @retval Number of bytes parsed.
685 **/
686 UINT32
687 EFIAPI
688 DumpAcpiHeader (
689 IN UINT8* Ptr
690 )
691 {
692 return ParseAcpi (
693 TRUE,
694 0,
695 "ACPI Table Header",
696 Ptr,
697 sizeof (EFI_ACPI_DESCRIPTION_HEADER),
698 PARSER_PARAMS (AcpiHeaderParser)
699 );
700 }
701
702 /**
703 This function parses the ACPI header as described by the AcpiHeaderParser.
704
705 This function optionally returns the signature, length and revision of the
706 ACPI table.
707
708 @param [in] Ptr Pointer to the start of the buffer.
709 @param [out] Signature Gets location of the ACPI table signature.
710 @param [out] Length Gets location of the length of the ACPI table.
711 @param [out] Revision Gets location of the revision of the ACPI table.
712
713 @retval Number of bytes parsed.
714 **/
715 UINT32
716 EFIAPI
717 ParseAcpiHeader (
718 IN UINT8* Ptr,
719 OUT CONST UINT32** Signature,
720 OUT CONST UINT32** Length,
721 OUT CONST UINT8** Revision
722 )
723 {
724 UINT32 BytesParsed;
725
726 BytesParsed = ParseAcpi (
727 FALSE,
728 0,
729 NULL,
730 Ptr,
731 sizeof (EFI_ACPI_DESCRIPTION_HEADER),
732 PARSER_PARAMS (AcpiHeaderParser)
733 );
734
735 *Signature = AcpiHdrInfo.Signature;
736 *Length = AcpiHdrInfo.Length;
737 *Revision = AcpiHdrInfo.Revision;
738
739 return BytesParsed;
740 }