]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c
a569c3c55406ab58536834e56ce9701f7edeffee
[mirror_edk2.git] / ShellPkg / Library / UefiShellAcpiViewCommandLib / AcpiParser.c
1 /** @file
2 ACPI parser
3
4 Copyright (c) 2016 - 2019, 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 indents and prints the ACPI table Field Name.
410
411 @param [in] Indent Number of spaces to add to the global table indent.
412 The global table indent is 0 by default; however
413 this value is updated on entry to the ParseAcpi()
414 by adding the indent value provided to ParseAcpi()
415 and restored back on exit.
416 Therefore the total indent in the output is
417 dependent on from where this function is called.
418 @param [in] FieldName Pointer to the Field Name.
419 **/
420 VOID
421 EFIAPI
422 PrintFieldName (
423 IN UINT32 Indent,
424 IN CONST CHAR16* FieldName
425 )
426 {
427 Print (
428 L"%*a%-*s : ",
429 gIndent + Indent,
430 "",
431 (OUTPUT_FIELD_COLUMN_WIDTH - gIndent - Indent),
432 FieldName
433 );
434 }
435
436 /**
437 This function is used to parse an ACPI table buffer.
438
439 The ACPI table buffer is parsed using the ACPI table parser information
440 specified by a pointer to an array of ACPI_PARSER elements. This parser
441 function iterates through each item on the ACPI_PARSER array and logs the
442 ACPI table fields.
443
444 This function can optionally be used to parse ACPI tables and fetch specific
445 field values. The ItemPtr member of the ACPI_PARSER structure (where used)
446 is updated by this parser function to point to the selected field data
447 (e.g. useful for variable length nested fields).
448
449 @param [in] Trace Trace the ACPI fields TRUE else only parse the
450 table.
451 @param [in] Indent Number of spaces to indent the output.
452 @param [in] AsciiName Optional pointer to an ASCII string that describes
453 the table being parsed.
454 @param [in] Ptr Pointer to the start of the buffer.
455 @param [in] Length Length of the buffer pointed by Ptr.
456 @param [in] Parser Pointer to an array of ACPI_PARSER structure that
457 describes the table being parsed.
458 @param [in] ParserItems Number of items in the ACPI_PARSER array.
459
460 @retval Number of bytes parsed.
461 **/
462 UINT32
463 EFIAPI
464 ParseAcpi (
465 IN BOOLEAN Trace,
466 IN UINT32 Indent,
467 IN CONST CHAR8* AsciiName OPTIONAL,
468 IN UINT8* Ptr,
469 IN UINT32 Length,
470 IN CONST ACPI_PARSER* Parser,
471 IN UINT32 ParserItems
472 )
473 {
474 UINT32 Index;
475 UINT32 Offset;
476 BOOLEAN HighLight;
477 UINTN OriginalAttribute;
478
479 //
480 // set local variables to suppress incorrect compiler/analyzer warnings
481 //
482 OriginalAttribute = 0;
483 Offset = 0;
484
485 // Increment the Indent
486 gIndent += Indent;
487
488 if (Trace && (AsciiName != NULL)){
489 HighLight = GetColourHighlighting ();
490
491 if (HighLight) {
492 OriginalAttribute = gST->ConOut->Mode->Attribute;
493 gST->ConOut->SetAttribute (
494 gST->ConOut,
495 EFI_TEXT_ATTR(EFI_YELLOW,
496 ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))
497 );
498 }
499 Print (
500 L"%*a%-*a :\n",
501 gIndent,
502 "",
503 (OUTPUT_FIELD_COLUMN_WIDTH - gIndent),
504 AsciiName
505 );
506 if (HighLight) {
507 gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute);
508 }
509 }
510
511 for (Index = 0; Index < ParserItems; Index++) {
512 if ((Offset + Parser[Index].Length) > Length) {
513 // We don't parse past the end of the max length specified
514 break;
515 }
516
517 if (GetConsistencyChecking () &&
518 (Offset != Parser[Index].Offset)) {
519 IncrementErrorCount ();
520 Print (
521 L"\nERROR: %a: Offset Mismatch for %s\n"
522 L"CurrentOffset = %d FieldOffset = %d\n",
523 AsciiName,
524 Parser[Index].NameStr,
525 Offset,
526 Parser[Index].Offset
527 );
528 }
529
530 if (Trace) {
531 // if there is a Formatter function let the function handle
532 // the printing else if a Format is specified in the table use
533 // the Format for printing
534 PrintFieldName (2, Parser[Index].NameStr);
535 if (Parser[Index].PrintFormatter != NULL) {
536 Parser[Index].PrintFormatter (Parser[Index].Format, Ptr);
537 } else if (Parser[Index].Format != NULL) {
538 switch (Parser[Index].Length) {
539 case 1:
540 DumpUint8 (Parser[Index].Format, Ptr);
541 break;
542 case 2:
543 DumpUint16 (Parser[Index].Format, Ptr);
544 break;
545 case 4:
546 DumpUint32 (Parser[Index].Format, Ptr);
547 break;
548 case 8:
549 DumpUint64 (Parser[Index].Format, Ptr);
550 break;
551 default:
552 Print (
553 L"\nERROR: %a: CANNOT PARSE THIS FIELD, Field Length = %d\n",
554 AsciiName,
555 Parser[Index].Length
556 );
557 } // switch
558
559 // Validating only makes sense if we are tracing
560 // the parsed table entries, to report by table name.
561 if (GetConsistencyChecking () &&
562 (Parser[Index].FieldValidator != NULL)) {
563 Parser[Index].FieldValidator (Ptr, Parser[Index].Context);
564 }
565 }
566 Print (L"\n");
567 } // if (Trace)
568
569 if (Parser[Index].ItemPtr != NULL) {
570 *Parser[Index].ItemPtr = (VOID*)Ptr;
571 }
572
573 Ptr += Parser[Index].Length;
574 Offset += Parser[Index].Length;
575 } // for
576
577 // Decrement the Indent
578 gIndent -= Indent;
579 return Offset;
580 }
581
582 /**
583 An array describing the ACPI Generic Address Structure.
584 The GasParser array is used by the ParseAcpi function to parse and/or trace
585 the GAS structure.
586 **/
587 STATIC CONST ACPI_PARSER GasParser[] = {
588 {L"Address Space ID", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},
589 {L"Register Bit Width", 1, 1, L"0x%x", NULL, NULL, NULL, NULL},
590 {L"Register Bit Offset", 1, 2, L"0x%x", NULL, NULL, NULL, NULL},
591 {L"Address Size", 1, 3, L"0x%x", NULL, NULL, NULL, NULL},
592 {L"Address", 8, 4, L"0x%lx", NULL, NULL, NULL, NULL}
593 };
594
595 /**
596 This function indents and traces the GAS structure as described by the GasParser.
597
598 @param [in] Ptr Pointer to the start of the buffer.
599 @param [in] Indent Number of spaces to indent the output.
600 @param [in] Length Length of the GAS structure buffer.
601
602 @retval Number of bytes parsed.
603 **/
604 UINT32
605 EFIAPI
606 DumpGasStruct (
607 IN UINT8* Ptr,
608 IN UINT32 Indent,
609 IN UINT32 Length
610 )
611 {
612 Print (L"\n");
613 return ParseAcpi (
614 TRUE,
615 Indent,
616 NULL,
617 Ptr,
618 Length,
619 PARSER_PARAMS (GasParser)
620 );
621 }
622
623 /**
624 This function traces the GAS structure as described by the GasParser.
625
626 @param [in] Format Optional format string for tracing the data.
627 @param [in] Ptr Pointer to the start of the buffer.
628 **/
629 VOID
630 EFIAPI
631 DumpGas (
632 IN CONST CHAR16* Format OPTIONAL,
633 IN UINT8* Ptr
634 )
635 {
636 DumpGasStruct (Ptr, 2, GAS_LENGTH);
637 }
638
639 /**
640 This function traces the ACPI header as described by the AcpiHeaderParser.
641
642 @param [in] Ptr Pointer to the start of the buffer.
643
644 @retval Number of bytes parsed.
645 **/
646 UINT32
647 EFIAPI
648 DumpAcpiHeader (
649 IN UINT8* Ptr
650 )
651 {
652 return ParseAcpi (
653 TRUE,
654 0,
655 "ACPI Table Header",
656 Ptr,
657 ACPI_DESCRIPTION_HEADER_LENGTH,
658 PARSER_PARAMS (AcpiHeaderParser)
659 );
660 }
661
662 /**
663 This function parses the ACPI header as described by the AcpiHeaderParser.
664
665 This function optionally returns the signature, length and revision of the
666 ACPI table.
667
668 @param [in] Ptr Pointer to the start of the buffer.
669 @param [out] Signature Gets location of the ACPI table signature.
670 @param [out] Length Gets location of the length of the ACPI table.
671 @param [out] Revision Gets location of the revision of the ACPI table.
672
673 @retval Number of bytes parsed.
674 **/
675 UINT32
676 EFIAPI
677 ParseAcpiHeader (
678 IN UINT8* Ptr,
679 OUT CONST UINT32** Signature,
680 OUT CONST UINT32** Length,
681 OUT CONST UINT8** Revision
682 )
683 {
684 UINT32 BytesParsed;
685
686 BytesParsed = ParseAcpi (
687 FALSE,
688 0,
689 NULL,
690 Ptr,
691 ACPI_DESCRIPTION_HEADER_LENGTH,
692 PARSER_PARAMS (AcpiHeaderParser)
693 );
694
695 *Signature = AcpiHdrInfo.Signature;
696 *Length = AcpiHdrInfo.Length;
697 *Revision = AcpiHdrInfo.Revision;
698
699 return BytesParsed;
700 }