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