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