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
10 #include <Library/UefiLib.h>
11 #include <Library/UefiBootServicesTableLib.h>
12 #include <Library/BaseMemoryLib.h>
13 #include "AcpiParser.h"
15 #include "AcpiViewConfig.h"
17 STATIC UINT32 gIndent
;
18 STATIC UINT32 mTableErrorCount
;
19 STATIC UINT32 mTableWarningCount
;
21 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo
;
24 An ACPI_PARSER array describing the ACPI header.
26 STATIC CONST ACPI_PARSER AcpiHeaderParser
[] = {
27 PARSE_ACPI_HEADER (&AcpiHdrInfo
)
31 This function resets the ACPI table error counter to Zero.
42 This function returns the ACPI table error count.
44 @retval Returns the count of errors detected in the ACPI tables.
51 return mTableErrorCount
;
55 This function resets the ACPI table warning counter to Zero.
62 mTableWarningCount
= 0;
66 This function returns the ACPI table warning count.
68 @retval Returns the count of warning detected in the ACPI tables.
75 return mTableWarningCount
;
79 This function increments the ACPI table error counter.
91 This function increments the ACPI table warning counter.
95 IncrementWarningCount (
103 This function verifies the ACPI table checksum.
105 This function verifies the checksum for the ACPI table and optionally
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.
112 @retval TRUE The checksum is OK.
113 @retval FALSE The checksum failed.
125 UINTN OriginalAttribute
;
128 // set local variables to suppress incorrect compiler/analyzer warnings
130 OriginalAttribute
= 0;
134 while (ByteCount
< Length
) {
135 Checksum
+= *(Ptr
++);
140 OriginalAttribute
= gST
->ConOut
->Mode
->Attribute
;
142 if (GetColourHighlighting ()) {
143 gST
->ConOut
->SetAttribute (
147 ((OriginalAttribute
&(BIT4
|BIT5
|BIT6
))>>4)
152 Print (L
"Table Checksum : OK\n\n");
154 IncrementErrorCount ();
155 if (GetColourHighlighting ()) {
156 gST
->ConOut
->SetAttribute (
160 ((OriginalAttribute
&(BIT4
|BIT5
|BIT6
))>>4)
165 Print (L
"Table Checksum : FAILED (0x%X)\n\n", Checksum
);
168 if (GetColourHighlighting ()) {
169 gST
->ConOut
->SetAttribute (gST
->ConOut
, OriginalAttribute
);
173 return (Checksum
== 0);
177 This function performs a raw data dump of the ACPI table.
179 @param [in] Ptr Pointer to the start of the table buffer.
180 @param [in] Length The length of the buffer.
191 UINTN AsciiBufferIndex
;
192 CHAR8 AsciiBuffer
[17];
195 AsciiBufferIndex
= 0;
197 Print (L
"Address : 0x%p\n", Ptr
);
198 Print (L
"Length : %d\n", Length
);
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) {
209 if ((*Ptr
>= ' ') && (*Ptr
< 0x7F)) {
210 AsciiBuffer
[AsciiBufferIndex
++] = *Ptr
;
212 AsciiBuffer
[AsciiBufferIndex
++] = '.';
215 Print (L
"%02X ", *Ptr
++);
220 // Justify the final line using spaces before printing
222 PartLineChars
= (Length
& 0x0F);
223 if (PartLineChars
!= 0) {
224 PartLineChars
= 48 - (PartLineChars
* 3);
225 if ((Length
& 0x0F) <= 8) {
229 while (PartLineChars
> 0) {
235 // Print ASCII data for the final line.
236 AsciiBuffer
[AsciiBufferIndex
] = '\0';
237 Print (L
" %a\n\n", AsciiBuffer
);
241 This function traces 1 byte of data as specified in the format string.
243 @param [in] Format The format string for tracing the data.
244 @param [in] Ptr Pointer to the start of the buffer.
249 IN CONST CHAR16
*Format
,
253 Print (Format
, *Ptr
);
257 This function traces 2 bytes of data as specified in the format string.
259 @param [in] Format The format string for tracing the data.
260 @param [in] Ptr Pointer to the start of the buffer.
265 IN CONST CHAR16
*Format
,
269 Print (Format
, *(UINT16
*)Ptr
);
273 This function traces 4 bytes of data as specified in the format string.
275 @param [in] Format The format string for tracing the data.
276 @param [in] Ptr Pointer to the start of the buffer.
281 IN CONST CHAR16
*Format
,
285 Print (Format
, *(UINT32
*)Ptr
);
289 This function traces 8 bytes of data as specified by the format string.
291 @param [in] Format The format string for tracing the data.
292 @param [in] Ptr Pointer to the start of the buffer.
297 IN CONST CHAR16
*Format
,
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.
306 Val
= *(UINT32
*)(Ptr
+ sizeof (UINT32
));
308 Val
= LShiftU64 (Val
, 32);
309 Val
|= (UINT64
)*(UINT32
*)Ptr
;
315 This function traces 3 characters which can be optionally
316 formated using the format string if specified.
318 If no format string is specified the Format must be NULL.
320 @param [in] Format Optional format string for tracing the data.
321 @param [in] Ptr Pointer to the start of the buffer.
326 IN CONST CHAR16
*Format OPTIONAL
,
331 (Format
!= NULL
) ? Format
: L
"%c%c%c",
339 This function traces 4 characters which can be optionally
340 formated using the format string if specified.
342 If no format string is specified the Format must be NULL.
344 @param [in] Format Optional format string for tracing the data.
345 @param [in] Ptr Pointer to the start of the buffer.
350 IN CONST CHAR16
*Format OPTIONAL
,
355 (Format
!= NULL
) ? Format
: L
"%c%c%c%c",
364 This function traces 6 characters which can be optionally
365 formated using the format string if specified.
367 If no format string is specified the Format must be NULL.
369 @param [in] Format Optional format string for tracing the data.
370 @param [in] Ptr Pointer to the start of the buffer.
375 IN CONST CHAR16
*Format OPTIONAL
,
380 (Format
!= NULL
) ? Format
: L
"%c%c%c%c%c%c",
391 This function traces 8 characters which can be optionally
392 formated using the format string if specified.
394 If no format string is specified the Format must be NULL.
396 @param [in] Format Optional format string for tracing the data.
397 @param [in] Ptr Pointer to the start of the buffer.
402 IN CONST CHAR16
*Format OPTIONAL
,
407 (Format
!= NULL
) ? Format
: L
"%c%c%c%c%c%c%c%c",
420 This function traces 12 characters which can be optionally
421 formated using the format string if specified.
423 If no format string is specified the Format must be NULL.
425 @param [in] Format Optional format string for tracing the data.
426 @param [in] Ptr Pointer to the start of the buffer.
431 IN CONST CHAR16
*Format OPTIONAL
,
436 (Format
!= NULL
) ? Format
: L
"%c%c%c%c%c%c%c%c%c%c%c%c",
453 This function indents and prints the ACPI table Field Name.
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.
468 IN CONST CHAR16
*FieldName
475 (OUTPUT_FIELD_COLUMN_WIDTH
- gIndent
- Indent
),
481 This function is used to parse an ACPI table buffer.
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
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).
493 @param [in] Trace Trace the ACPI fields TRUE else only parse the
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.
504 @retval Number of bytes parsed.
511 IN CONST CHAR8
*AsciiName OPTIONAL
,
514 IN CONST ACPI_PARSER
*Parser
,
515 IN UINT32 ParserItems
521 UINTN OriginalAttribute
;
524 // set local variables to suppress incorrect compiler/analyzer warnings
526 OriginalAttribute
= 0;
529 // Increment the Indent
532 if (Trace
&& (AsciiName
!= NULL
)) {
533 HighLight
= GetColourHighlighting ();
536 OriginalAttribute
= gST
->ConOut
->Mode
->Attribute
;
537 gST
->ConOut
->SetAttribute (
541 ((OriginalAttribute
&(BIT4
|BIT5
|BIT6
))>>4)
550 (OUTPUT_FIELD_COLUMN_WIDTH
- gIndent
),
554 gST
->ConOut
->SetAttribute (gST
->ConOut
, OriginalAttribute
);
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
;
566 // We don't parse past the end of the max length specified
570 if (GetConsistencyChecking () &&
571 (Offset
!= Parser
[Index
].Offset
))
573 IncrementErrorCount ();
575 L
"\nERROR: %a: Offset Mismatch for %s\n"
576 L
"CurrentOffset = %d FieldOffset = %d\n",
578 Parser
[Index
].NameStr
,
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
) {
594 DumpUint8 (Parser
[Index
].Format
, Ptr
);
597 DumpUint16 (Parser
[Index
].Format
, Ptr
);
600 DumpUint32 (Parser
[Index
].Format
, Ptr
);
603 DumpUint64 (Parser
[Index
].Format
, Ptr
);
607 L
"\nERROR: %a: CANNOT PARSE THIS FIELD, Field Length = %d\n",
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
))
619 Parser
[Index
].FieldValidator (Ptr
, Parser
[Index
].Context
);
625 if (Parser
[Index
].ItemPtr
!= NULL
) {
626 *Parser
[Index
].ItemPtr
= (VOID
*)Ptr
;
629 Ptr
+= Parser
[Index
].Length
;
630 Offset
+= Parser
[Index
].Length
;
633 // Decrement the Indent
639 An array describing the ACPI Generic Address Structure.
640 The GasParser array is used by the ParseAcpi function to parse and/or trace
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
}
652 This function indents and traces the GAS structure as described by the GasParser.
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.
658 @retval Number of bytes parsed.
675 PARSER_PARAMS (GasParser
)
680 This function traces the GAS structure as described by the GasParser.
682 @param [in] Format Optional format string for tracing the data.
683 @param [in] Ptr Pointer to the start of the buffer.
688 IN CONST CHAR16
*Format OPTIONAL
,
692 DumpGasStruct (Ptr
, 2, sizeof (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE
));
696 This function traces the ACPI header as described by the AcpiHeaderParser.
698 @param [in] Ptr Pointer to the start of the buffer.
700 @retval Number of bytes parsed.
713 sizeof (EFI_ACPI_DESCRIPTION_HEADER
),
714 PARSER_PARAMS (AcpiHeaderParser
)
719 This function parses the ACPI header as described by the AcpiHeaderParser.
721 This function optionally returns the signature, length and revision of the
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.
729 @retval Number of bytes parsed.
735 OUT CONST UINT32
**Signature
,
736 OUT CONST UINT32
**Length
,
737 OUT CONST UINT8
**Revision
742 BytesParsed
= ParseAcpi (
747 sizeof (EFI_ACPI_DESCRIPTION_HEADER
),
748 PARSER_PARAMS (AcpiHeaderParser
)
751 *Signature
= AcpiHdrInfo
.Signature
;
752 *Length
= AcpiHdrInfo
.Length
;
753 *Revision
= AcpiHdrInfo
.Revision
;
759 This function is used to parse an ACPI table bitfield buffer.
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.
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).
770 ItemPtr member of ACPI_PARSER is not supported with this function.
772 @param [in] Trace Trace the ACPI fields TRUE else only parse the
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.
783 @retval Number of bits parsed.
790 IN CONST CHAR8
*AsciiName OPTIONAL
,
793 IN CONST ACPI_PARSER
*Parser
,
794 IN UINT32 ParserItems
800 UINTN OriginalAttribute
;
805 if ((Length
== 0) || (Length
> 8)) {
806 IncrementErrorCount ();
808 L
"\nERROR: Bitfield Length(%d) is zero or exceeding the 64 bit limit.\n",
815 // set local variables to suppress incorrect compiler/analyzer warnings
817 OriginalAttribute
= 0;
820 // Increment the Indent
823 CopyMem ((VOID
*)&BitsData
, (VOID
*)Ptr
, Length
);
824 if (Trace
&& (AsciiName
!= NULL
)) {
825 HighLight
= GetColourHighlighting ();
828 OriginalAttribute
= gST
->ConOut
->Mode
->Attribute
;
829 gST
->ConOut
->SetAttribute (
833 ((OriginalAttribute
&(BIT4
|BIT5
|BIT6
))>>4)
842 (OUTPUT_FIELD_COLUMN_WIDTH
- gIndent
),
846 gST
->ConOut
->SetAttribute (gST
->ConOut
, OriginalAttribute
);
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
;
858 // We don't parse past the end of the max length specified
862 if (Parser
[Index
].Length
== 0) {
863 IncrementErrorCount ();
864 // don't parse the bitfield whose length is zero
866 L
"\nERROR: %a: Cannot parse this field, Field Length = %d\n",
872 if (GetConsistencyChecking () &&
873 (Offset
!= Parser
[Index
].Offset
))
875 IncrementErrorCount ();
877 L
"\nERROR: %a: Offset Mismatch for %s\n"
878 L
"CurrentOffset = %d FieldOffset = %d\n",
880 Parser
[Index
].NameStr
,
886 // extract Bitfield data for the current item
887 Data
= RShiftU64 (BitsData
, Parser
[Index
].Offset
) & ~(LShiftU64 (~0ULL, Parser
[Index
].Length
));
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
901 DumpUint8 (Parser
[Index
].Format
, (UINT8
*)&Data
);
904 DumpUint16 (Parser
[Index
].Format
, (UINT8
*)&Data
);
908 DumpUint32 (Parser
[Index
].Format
, (UINT8
*)&Data
);
914 DumpUint64 (Parser
[Index
].Format
, (UINT8
*)&Data
);
918 L
"\nERROR: %a: CANNOT PARSE THIS FIELD, Field Length = %d\n",
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
))
930 Parser
[Index
].FieldValidator ((UINT8
*)&Data
, Parser
[Index
].Context
);
936 Offset
+= Parser
[Index
].Length
;
939 // Decrement the Indent