4 Copyright (c) 2020, Arm Limited.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
8 - ACPI for the Armv8 RAS Extensions 1.1 Platform Design Document,
9 dated 28 September 2020.
10 (https://developer.arm.com/documentation/den0085/0101/)
13 #include <Library/PrintLib.h>
14 #include <Library/UefiLib.h>
15 #include <IndustryStandard/ArmErrorSourceTable.h>
16 #include "AcpiParser.h"
18 #include "AcpiViewConfig.h"
21 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo
;
22 STATIC UINT8
*AestNodeType
;
23 STATIC UINT16
*AestNodeLength
;
24 STATIC UINT32
*NodeDataOffset
;
25 STATIC UINT32
*NodeInterfaceOffset
;
26 STATIC UINT32
*NodeInterruptArrayOffset
;
27 STATIC UINT32
*NodeInterruptCount
;
28 STATIC UINT32
*ProcessorId
;
29 STATIC UINT8
*ProcessorFlags
;
30 STATIC UINT8
*ProcessorResourceType
;
33 Validate Processor Flags.
35 @param [in] Ptr Pointer to the start of the field data.
36 @param [in] Context Pointer to context specific information e.g. this
37 could be a pointer to the ACPI table header.
42 ValidateProcessorFlags (
47 // If the global or shared node flag is set then the ACPI Processor ID
48 // field must be set to 0 and ignored.
49 if (((*Ptr
& 0x3) != 0) && (*ProcessorId
!= 0)) {
50 IncrementErrorCount ();
52 L
"\nERROR: 'ACPI Processor ID' field must be set to 0 for global"
59 Validate GIC Interface Type.
61 @param [in] Ptr Pointer to the start of the field data.
62 @param [in] Context Pointer to context specific information e.g. this
63 could be a pointer to the ACPI table header.
68 ValidateGicInterfaceType (
73 UINT32 GicInterfaceType
;
75 GicInterfaceType
= *(UINT32
*)Ptr
;
76 if (GicInterfaceType
> 3) {
77 IncrementErrorCount ();
78 Print (L
"\nError: Invalid GIC Interface type %d", GicInterfaceType
);
83 Validate Interface Type.
85 @param [in] Ptr Pointer to the start of the field data.
86 @param [in] Context Pointer to context specific information e.g. this
87 could be a pointer to the ACPI table header.
92 ValidateInterfaceType (
98 IncrementErrorCount ();
99 Print (L
"\nError: Interface type should be 0 or 1");
104 Validate Interrupt Type.
106 @param [in] Ptr Pointer to the start of the field data.
107 @param [in] Context Pointer to context specific information e.g. this
108 could be a pointer to the ACPI table header.
113 ValidateInterruptType (
119 IncrementErrorCount ();
120 Print (L
"\nError: Interrupt type should be 0 or 1");
125 Validate interrupt flags.
127 @param [in] Ptr Pointer to the start of the field data.
128 @param [in] Context Pointer to context specific information e.g. this
129 could be a pointer to the ACPI table header.
134 ValidateInterruptFlags (
139 if ((*Ptr
& 0xfe) != 0) {
140 IncrementErrorCount ();
141 Print (L
"\nError: Reserved Flag bits not set to 0");
146 Dumps 16 bytes of data.
148 @param [in] Format Optional format string for tracing the data.
149 @param [in] Ptr Pointer to the start of the buffer.
153 DumpVendorSpecificData (
154 IN CONST CHAR16
*Format OPTIONAL
,
159 L
"%02X %02X %02X %02X %02X %02X %02X %02X\n",
171 L
"%*a %02X %02X %02X %02X %02X %02X %02X %02X",
172 OUTPUT_FIELD_COLUMN_WIDTH
,
186 An ACPI_PARSER array describing the ACPI AEST Table.
188 STATIC CONST ACPI_PARSER AestParser
[] = {
189 PARSE_ACPI_HEADER (&AcpiHdrInfo
)
193 An ACPI_PARSER array describing the AEST Node Header.
195 STATIC CONST ACPI_PARSER AestNodeHeaderParser
[] = {
196 { L
"Type", 1, 0, L
"%d", NULL
, (VOID
**)&AestNodeType
, NULL
, NULL
},
197 { L
"Length", 2, 1, L
"%d", NULL
, (VOID
**)&AestNodeLength
, NULL
, NULL
},
198 { L
"Reserved", 1, 3, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
199 { L
"Node Data Offset", 4, 4, L
"%d", NULL
, (VOID
**)&NodeDataOffset
, NULL
, NULL
},
200 { L
"Node Interface Offset", 4, 8, L
"%d", NULL
,
201 (VOID
**)&NodeInterfaceOffset
, NULL
, NULL
},
202 { L
"Node Interrupt Array Offset", 4, 12, L
"%d", NULL
,
203 (VOID
**)&NodeInterruptArrayOffset
, NULL
, NULL
},
204 { L
"Node Interrupt Count", 4, 16, L
"%d", NULL
,
205 (VOID
**)&NodeInterruptCount
, NULL
, NULL
},
206 { L
"Timestamp Rate", 8, 20, L
"%ld", NULL
, NULL
, NULL
, NULL
},
207 { L
"Reserved1", 8, 28, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
208 { L
"Error Injection Countdown Rate", 8, 36, L
"%ld", NULL
, NULL
, NULL
, NULL
}
209 // Node specific data...
211 // Node interrupt array...
215 An ACPI_PARSER array describing the Processor error node specific data.
217 STATIC CONST ACPI_PARSER AestProcessorStructure
[] = {
218 { L
"ACPI Processor ID", 4, 0, L
"0x%x", NULL
, (VOID
**)&ProcessorId
, NULL
, NULL
},
219 { L
"Resource Type", 1, 4, L
"%d", NULL
, (VOID
**)&ProcessorResourceType
, NULL
,
221 { L
"Reserved", 1, 5, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
222 { L
"Flags", 1, 6, L
"0x%x", NULL
, (VOID
**)&ProcessorFlags
,
223 ValidateProcessorFlags
, NULL
},
224 { L
"Revision", 1, 7, L
"%d", NULL
, NULL
, NULL
, NULL
},
225 { L
"Processor Affinity Level Indicator", 8, 8, L
"0x%lx", NULL
, NULL
, NULL
,
227 // Resource specific data...
231 An ACPI_PARSER array describing the processor cache resource substructure.
233 STATIC CONST ACPI_PARSER AestProcessorCacheResourceSubstructure
[] = {
234 { L
"Cache reference ID", 4, 0, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
235 { L
"Reserved", 4, 4, L
"%d", NULL
, NULL
, NULL
, NULL
}
239 An ACPI_PARSER array describing the processor TLB resource substructure.
241 STATIC CONST ACPI_PARSER AestProcessorTlbResourceSubstructure
[] = {
242 { L
"TLB reference ID", 4, 0, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
243 { L
"Reserved", 4, 4, L
"%d", NULL
, NULL
, NULL
, NULL
}
247 An ACPI_PARSER array describing the processor generic resource substructure.
249 STATIC CONST ACPI_PARSER AestProcessorGenericResourceSubstructure
[] = {
250 { L
"Vendor-defined data", 4, 0, L
"%x", NULL
, NULL
, NULL
, NULL
}
254 An ACPI_PARSER array describing the memory controller structure.
256 STATIC CONST ACPI_PARSER AestMemoryControllerStructure
[] = {
257 { L
"Proximity Domain", 4, 0, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
261 An ACPI_PARSER array describing the SMMU structure.
263 STATIC CONST ACPI_PARSER AestSmmuStructure
[] = {
264 { L
"IORT Node reference ID", 4, 0, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
265 { L
"SubComponent reference ID", 4, 4, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
269 An ACPI_PARSER array describing the vendor-defined structure.
271 STATIC CONST ACPI_PARSER AestVendorDefinedStructure
[] = {
272 { L
"Hardware ID", 4, 0, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
273 { L
"Unique ID", 4, 4, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
274 { L
"Vendor-specific data", 16, 8, NULL
, DumpVendorSpecificData
, NULL
, NULL
}
278 An ACPI_PARSER array describing the GIC structure.
280 STATIC CONST ACPI_PARSER AestGicStructure
[] = {
281 { L
"GIC Interface Type", 4, 0, L
"0x%x", NULL
, NULL
, ValidateGicInterfaceType
,
283 { L
"GIC Interface reference ID", 4, 4, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
287 An ACPI_PARSER array describing the node interface.
289 STATIC CONST ACPI_PARSER AestNodeInterface
[] = {
290 { L
"Interface Type", 1, 0, L
"%d", NULL
, NULL
, ValidateInterfaceType
, NULL
},
291 { L
"Reserved", 3, 1, L
"%x %x %x", Dump3Chars
, NULL
, NULL
, NULL
},
292 { L
"Flags", 4, 4, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
293 { L
"Base Address", 8, 8, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
294 { L
"Start Error Record Index", 4, 16, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
295 { L
"Number of Error Records", 4, 20, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
296 { L
"Error Records Implemented", 8, 24, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
297 { L
"Error Records Support", 8, 32, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
298 { L
"Addressing mode", 8, 40, L
"0x%lx", NULL
, NULL
, NULL
, NULL
}
302 An ACPI_PARSER array describing the node interrupts.
304 STATIC CONST ACPI_PARSER AestNodeInterrupt
[] = {
305 { L
"Interrupt Type", 1, 0, L
"%d", NULL
, NULL
, ValidateInterruptType
, NULL
},
306 { L
"Reserved", 2, 1, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
307 { L
"Interrupt Flags", 1, 3, L
"0x%x", NULL
, NULL
, ValidateInterruptFlags
, NULL
},
308 { L
"Interrupt GSIV", 4, 4, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
309 { L
"ID", 1, 8, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
310 { L
"Reserved1", 3, 9, L
"%x %x %x", Dump3Chars
, NULL
, NULL
, NULL
}
314 Parses the Processor Error Node structure along with its resource
317 @param [in] Ptr Pointer to the start of the Processor node.
318 @param [in] Length Maximum length of the Processor node.
335 PARSER_PARAMS (AestProcessorStructure
)
338 // Check if the values used to control the parsing logic have been
339 // successfully read.
340 if ((ProcessorId
== NULL
) ||
341 (ProcessorResourceType
== NULL
) ||
342 (ProcessorFlags
== NULL
))
344 IncrementErrorCount ();
346 L
"ERROR: Insufficient Processor Error Node length. Length = %d.\n",
352 switch (*ProcessorResourceType
) {
353 case EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_CACHE
:
360 PARSER_PARAMS (AestProcessorCacheResourceSubstructure
)
363 case EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_TLB
:
370 PARSER_PARAMS (AestProcessorTlbResourceSubstructure
)
373 case EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_GENERIC
:
380 PARSER_PARAMS (AestProcessorGenericResourceSubstructure
)
384 IncrementErrorCount ();
385 Print (L
"ERROR: Invalid Processor Resource Type.");
391 Parses the Memory Controller node.
393 @param [in] Ptr Pointer to the start of the Memory Controller node.
394 @param [in] Length Maximum length of the Memory Controller node.
398 DumpMemoryControllerNode (
409 PARSER_PARAMS (AestMemoryControllerStructure
)
414 Parses the SMMU node.
416 @param [in] Ptr Pointer to the start of the SMMU node.
417 @param [in] Length Maximum length of the SMMU node.
432 PARSER_PARAMS (AestSmmuStructure
)
437 Parses the Vendor-defined structure.
439 @param [in] Ptr Pointer to the start of the Vendor-defined node.
440 @param [in] Length Maximum length of the Vendor-defined node.
444 DumpVendorDefinedNode (
455 PARSER_PARAMS (AestVendorDefinedStructure
)
462 @param [in] Ptr Pointer to the start of the GIC node.
463 @param [in] Length Maximum length of the GIC node.
478 PARSER_PARAMS (AestGicStructure
)
483 Parses the Node Interface structure.
485 @param [in] Ptr Pointer to the start of the Node Interface Structure.
486 @param [in] Length Maximum length of the Node Interface Structure.
501 PARSER_PARAMS (AestNodeInterface
)
506 Parses the Node Interrupts Structure.
508 @param [in] Ptr Pointer to the start of the Node Interrupt array.
509 @param [in] Length Maximum length of the Node Interrupt array.
510 @param [in] InterruptCount Number if interrupts in the Node Interrupts array.
517 IN UINT32 InterruptCount
524 if (Length
< (InterruptCount
* sizeof (EFI_ACPI_AEST_INTERRUPT_STRUCT
))) {
525 IncrementErrorCount ();
527 L
"ERROR: Node not long enough for Interrupt Array.\n" \
528 L
" Length left = %d, Required = %d, Interrupt Count = %d\n",
530 (InterruptCount
* sizeof (EFI_ACPI_AEST_INTERRUPT_STRUCT
)),
537 for (Index
= 0; Index
< InterruptCount
; Index
++) {
541 "Node Interrupt [%d]",
545 Offset
+= ParseAcpi (
551 PARSER_PARAMS (AestNodeInterrupt
)
557 Parses a single AEST Node Structure.
559 @param [in] Ptr Pointer to the start of the Node.
560 @param [in] Length Maximum length of the Node.
561 @param [in] NodeType AEST node type.
562 @param [in] DataOffset Offset to the node data.
563 @param [in] InterfaceOffset Offset to the node interface data.
564 @param [in] InterruptArrayOffset Offset to the node interrupt array.
565 @param [in] InterruptCount Number of interrupts.
569 DumpAestNodeStructure (
573 IN UINT32 DataOffset
,
574 IN UINT32 InterfaceOffset
,
575 IN UINT32 InterruptArrayOffset
,
576 IN UINT32 InterruptCount
580 UINT32 RemainingLength
;
589 PARSER_PARAMS (AestNodeHeaderParser
)
592 if ((Offset
> DataOffset
) || (DataOffset
> Length
)) {
593 IncrementErrorCount ();
595 L
"ERROR: Invalid Node Data Offset: %d.\n" \
596 L
" It should be between %d and %d.\n",
603 if ((Offset
> InterfaceOffset
) || (InterfaceOffset
> Length
)) {
604 IncrementErrorCount ();
606 L
"ERROR: Invalid Node Interface Offset: %d.\n" \
607 L
" It should be between %d and %d.\n",
614 if ((Offset
> InterruptArrayOffset
) || (InterruptArrayOffset
> Length
)) {
615 IncrementErrorCount ();
617 L
"ERROR: Invalid Node Interrupt Array Offset: %d.\n" \
618 L
" It should be between %d and %d.\n",
619 InterruptArrayOffset
,
625 // Parse Node Data Field.
626 NodeDataPtr
= Ptr
+ DataOffset
;
627 RemainingLength
= Length
- DataOffset
;
629 case EFI_ACPI_AEST_NODE_TYPE_PROCESSOR
:
630 DumpProcessorNode (NodeDataPtr
, RemainingLength
);
632 case EFI_ACPI_AEST_NODE_TYPE_MEMORY
:
633 DumpMemoryControllerNode (NodeDataPtr
, RemainingLength
);
635 case EFI_ACPI_AEST_NODE_TYPE_SMMU
:
636 DumpSmmuNode (NodeDataPtr
, RemainingLength
);
638 case EFI_ACPI_AEST_NODE_TYPE_VENDOR_DEFINED
:
639 DumpVendorDefinedNode (NodeDataPtr
, RemainingLength
);
641 case EFI_ACPI_AEST_NODE_TYPE_GIC
:
642 DumpGicNode (NodeDataPtr
, RemainingLength
);
645 IncrementErrorCount ();
646 Print (L
"ERROR: Invalid Error Node Type.\n");
650 // Parse the Interface Field.
652 Ptr
+ InterfaceOffset
,
653 Length
- InterfaceOffset
656 // Parse the Node Interrupt Array.
658 Ptr
+ InterruptArrayOffset
,
659 Length
- InterruptArrayOffset
,
667 This function parses the ACPI AEST table.
668 When trace is enabled this function parses the AEST table and
669 traces the ACPI table fields.
671 This function also performs validation of the ACPI table fields.
673 @param [in] Trace If TRUE, trace the ACPI fields.
674 @param [in] Ptr Pointer to the start of the buffer.
675 @param [in] AcpiTableLength Length of the ACPI table.
676 @param [in] AcpiTableRevision Revision of the ACPI table.
683 IN UINT32 AcpiTableLength
,
684 IN UINT8 AcpiTableRevision
700 PARSER_PARAMS (AestParser
)
703 while (Offset
< AcpiTableLength
) {
704 NodePtr
= Ptr
+ Offset
;
711 AcpiTableLength
- Offset
,
712 PARSER_PARAMS (AestNodeHeaderParser
)
715 // Check if the values used to control the parsing logic have been
716 // successfully read.
717 if ((AestNodeType
== NULL
) ||
718 (AestNodeLength
== NULL
) ||
719 (NodeDataOffset
== NULL
) ||
720 (NodeInterfaceOffset
== NULL
) ||
721 (NodeInterruptArrayOffset
== NULL
) ||
722 (NodeInterruptCount
== NULL
))
724 IncrementErrorCount ();
726 L
"ERROR: Insufficient length left for Node Structure.\n" \
727 L
" Length left = %d.\n",
728 AcpiTableLength
- Offset
733 // Validate AEST Node length
734 if ((*AestNodeLength
== 0) ||
735 ((Offset
+ (*AestNodeLength
)) > AcpiTableLength
))
737 IncrementErrorCount ();
739 L
"ERROR: Invalid AEST Node length. " \
740 L
"Length = %d. Offset = %d. AcpiTableLength = %d.\n",
748 DumpAestNodeStructure (
753 *NodeInterfaceOffset
,
754 *NodeInterruptArrayOffset
,
758 Offset
+= *AestNodeLength
;