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