--- /dev/null
+/** @file\r
+ AEST table parser\r
+\r
+ Copyright (c) 2020, Arm Limited.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+ @par Reference(s):\r
+ - ACPI for the Armv8 RAS Extensions 1.1 Platform Design Document,\r
+ dated 28 September 2020.\r
+ (https://developer.arm.com/documentation/den0085/0101/)\r
+**/\r
+\r
+#include <Library/PrintLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <IndustryStandard/ArmErrorSourceTable.h>\r
+#include "AcpiParser.h"\r
+#include "AcpiView.h"\r
+#include "AcpiViewConfig.h"\r
+\r
+// Local variables\r
+STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;\r
+STATIC UINT8* AestNodeType;\r
+STATIC UINT16* AestNodeLength;\r
+STATIC UINT32* NodeDataOffset;\r
+STATIC UINT32* NodeInterfaceOffset;\r
+STATIC UINT32* NodeInterruptArrayOffset;\r
+STATIC UINT32* NodeInterruptCount;\r
+STATIC UINT32* ProcessorId;\r
+STATIC UINT8* ProcessorFlags;\r
+STATIC UINT8* ProcessorResourceType;\r
+\r
+/**\r
+ Validate Processor Flags.\r
+\r
+ @param [in] Ptr Pointer to the start of the field data.\r
+ @param [in] Context Pointer to context specific information e.g. this\r
+ could be a pointer to the ACPI table header.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+ValidateProcessorFlags (\r
+ IN UINT8* Ptr,\r
+ IN VOID* Context\r
+ )\r
+{\r
+ // If the global or shared node flag is set then the ACPI Processor ID\r
+ // field must be set to 0 and ignored.\r
+ if (((*Ptr & 0x3) != 0) && (*ProcessorId != 0)) {\r
+ IncrementErrorCount ();\r
+ Print (L"\nERROR: 'ACPI Processor ID' field must be set to 0 for global"\r
+ L" or shared nodes.");\r
+ }\r
+}\r
+\r
+/**\r
+ Validate GIC Interface Type.\r
+\r
+ @param [in] Ptr Pointer to the start of the field data.\r
+ @param [in] Context Pointer to context specific information e.g. this\r
+ could be a pointer to the ACPI table header.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+ValidateGicInterfaceType (\r
+ IN UINT8* Ptr,\r
+ IN VOID* Context\r
+ )\r
+{\r
+ UINT32 GicInterfaceType;\r
+\r
+ GicInterfaceType = *(UINT32*)Ptr;\r
+ if (GicInterfaceType > 3) {\r
+ IncrementErrorCount ();\r
+ Print (L"\nError: Invalid GIC Interface type %d", GicInterfaceType);\r
+ }\r
+}\r
+\r
+/**\r
+ Validate Interface Type.\r
+\r
+ @param [in] Ptr Pointer to the start of the field data.\r
+ @param [in] Context Pointer to context specific information e.g. this\r
+ could be a pointer to the ACPI table header.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+ValidateInterfaceType (\r
+ IN UINT8* Ptr,\r
+ IN VOID* Context\r
+ )\r
+{\r
+ if (*Ptr > 1) {\r
+ IncrementErrorCount ();\r
+ Print (L"\nError: Interface type should be 0 or 1");\r
+ }\r
+}\r
+\r
+/**\r
+ Validate Interrupt Type.\r
+\r
+ @param [in] Ptr Pointer to the start of the field data.\r
+ @param [in] Context Pointer to context specific information e.g. this\r
+ could be a pointer to the ACPI table header.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+ValidateInterruptType (\r
+ IN UINT8* Ptr,\r
+ IN VOID* Context\r
+ )\r
+{\r
+ if (*Ptr > 1) {\r
+ IncrementErrorCount ();\r
+ Print (L"\nError: Interrupt type should be 0 or 1");\r
+ }\r
+}\r
+\r
+/**\r
+ Validate interrupt flags.\r
+\r
+ @param [in] Ptr Pointer to the start of the field data.\r
+ @param [in] Context Pointer to context specific information e.g. this\r
+ could be a pointer to the ACPI table header.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+ValidateInterruptFlags (\r
+ IN UINT8* Ptr,\r
+ IN VOID* Context\r
+ )\r
+{\r
+ if ((*Ptr & 0xfe) != 0) {\r
+ IncrementErrorCount ();\r
+ Print (L"\nError: Reserved Flag bits not set to 0");\r
+ }\r
+}\r
+\r
+/**\r
+ Dumps 16 bytes of data.\r
+\r
+ @param [in] Format Optional format string for tracing the data.\r
+ @param [in] Ptr Pointer to the start of the buffer.\r
+**/\r
+VOID\r
+EFIAPI\r
+DumpVendorSpecificData (\r
+ IN CONST CHAR16* Format OPTIONAL,\r
+ IN UINT8* Ptr\r
+ )\r
+{\r
+ Print (\r
+ L"%02X %02X %02X %02X %02X %02X %02X %02X\n",\r
+ Ptr[0],\r
+ Ptr[1],\r
+ Ptr[2],\r
+ Ptr[3],\r
+ Ptr[4],\r
+ Ptr[5],\r
+ Ptr[6],\r
+ Ptr[7]\r
+ );\r
+\r
+ Print (\r
+ L"%*a %02X %02X %02X %02X %02X %02X %02X %02X",\r
+ OUTPUT_FIELD_COLUMN_WIDTH,\r
+ "",\r
+ Ptr[8],\r
+ Ptr[9],\r
+ Ptr[10],\r
+ Ptr[11],\r
+ Ptr[12],\r
+ Ptr[13],\r
+ Ptr[14],\r
+ Ptr[15]\r
+ );\r
+}\r
+\r
+/**\r
+ An ACPI_PARSER array describing the ACPI AEST Table.\r
+**/\r
+STATIC CONST ACPI_PARSER AestParser[] = {\r
+ PARSE_ACPI_HEADER (&AcpiHdrInfo)\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the AEST Node Header.\r
+**/\r
+STATIC CONST ACPI_PARSER AestNodeHeaderParser[] = {\r
+ {L"Type", 1, 0, L"%d", NULL, (VOID**)&AestNodeType, NULL, NULL},\r
+ {L"Length", 2, 1, L"%d", NULL, (VOID**)&AestNodeLength, NULL, NULL},\r
+ {L"Reserved", 1, 3, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Node Data Offset", 4, 4, L"%d", NULL, (VOID**)&NodeDataOffset, NULL, NULL},\r
+ {L"Node Interface Offset", 4, 8, L"%d", NULL,\r
+ (VOID**)&NodeInterfaceOffset, NULL, NULL},\r
+ {L"Node Interrupt Array Offset", 4, 12, L"%d", NULL,\r
+ (VOID**)&NodeInterruptArrayOffset, NULL, NULL},\r
+ {L"Node Interrupt Count", 4, 16, L"%d", NULL,\r
+ (VOID**)&NodeInterruptCount, NULL, NULL},\r
+ {L"Timestamp Rate", 8, 20, L"%ld", NULL, NULL, NULL, NULL},\r
+ {L"Reserved1", 8, 28, L"0x%lx", NULL, NULL, NULL, NULL},\r
+ {L"Error Injection Countdown Rate", 8, 36, L"%ld", NULL, NULL, NULL, NULL}\r
+ // Node specific data...\r
+ // Node interface...\r
+ // Node interrupt array...\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the Processor error node specific data.\r
+**/\r
+STATIC CONST ACPI_PARSER AestProcessorStructure[] = {\r
+ {L"ACPI Processor ID", 4, 0, L"0x%x", NULL, (VOID**)&ProcessorId, NULL, NULL},\r
+ {L"Resource Type", 1, 4, L"%d", NULL, (VOID**)&ProcessorResourceType, NULL,\r
+ NULL},\r
+ {L"Reserved", 1, 5, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Flags", 1, 6, L"0x%x", NULL, (VOID**)&ProcessorFlags,\r
+ ValidateProcessorFlags, NULL},\r
+ {L"Revision", 1, 7, L"%d", NULL, NULL, NULL, NULL},\r
+ {L"Processor Affinity Level Indicator", 8, 8, L"0x%lx", NULL, NULL, NULL,\r
+ NULL},\r
+ // Resource specific data...\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the processor cache resource substructure.\r
+**/\r
+STATIC CONST ACPI_PARSER AestProcessorCacheResourceSubstructure[] = {\r
+ {L"Cache reference ID", 4, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Reserved", 4, 4, L"%d", NULL, NULL, NULL, NULL}\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the processor TLB resource substructure.\r
+**/\r
+STATIC CONST ACPI_PARSER AestProcessorTlbResourceSubstructure[] = {\r
+ {L"TLB reference ID", 4, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Reserved", 4, 4, L"%d", NULL, NULL, NULL, NULL}\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the processor generic resource substructure.\r
+**/\r
+STATIC CONST ACPI_PARSER AestProcessorGenericResourceSubstructure[] = {\r
+ {L"Vendor-defined data", 4, 0, L"%x", NULL, NULL, NULL, NULL}\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the memory controller structure.\r
+**/\r
+STATIC CONST ACPI_PARSER AestMemoryControllerStructure[] = {\r
+ {L"Proximity Domain", 4, 0, L"0x%x", NULL, NULL, NULL, NULL}\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the SMMU structure.\r
+**/\r
+STATIC CONST ACPI_PARSER AestSmmuStructure[] = {\r
+ {L"IORT Node reference ID", 4, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"SubComponent reference ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the vendor-defined structure.\r
+**/\r
+STATIC CONST ACPI_PARSER AestVendorDefinedStructure[] = {\r
+ {L"Hardware ID", 4, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Unique ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Vendor-specific data", 16, 8, NULL, DumpVendorSpecificData, NULL, NULL}\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the GIC structure.\r
+**/\r
+STATIC CONST ACPI_PARSER AestGicStructure[] = {\r
+ {L"GIC Interface Type", 4, 0, L"0x%x", NULL, NULL, ValidateGicInterfaceType,\r
+ NULL},\r
+ {L"GIC Interface reference ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the node interface.\r
+**/\r
+STATIC CONST ACPI_PARSER AestNodeInterface[] = {\r
+ {L"Interface Type", 1, 0, L"%d", NULL, NULL, ValidateInterfaceType, NULL},\r
+ {L"Reserved", 3, 1, L"%x %x %x", Dump3Chars, NULL, NULL, NULL},\r
+ {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL},\r
+ {L"Start Error Record Index", 4, 16, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Number of Error Records", 4, 20, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Error Records Implemented", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL},\r
+ {L"Error Records Support", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL},\r
+ {L"Addressing mode", 8, 40, L"0x%lx", NULL, NULL, NULL, NULL}\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the node interrupts.\r
+**/\r
+STATIC CONST ACPI_PARSER AestNodeInterrupt[] = {\r
+ {L"Interrupt Type", 1, 0, L"%d", NULL, NULL, ValidateInterruptType, NULL},\r
+ {L"Reserved", 2, 1, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Interrupt Flags", 1, 3, L"0x%x", NULL, NULL, ValidateInterruptFlags, NULL},\r
+ {L"Interrupt GSIV", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"ID", 1, 8, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Reserved1", 3, 9, L"%x %x %x", Dump3Chars, NULL, NULL, NULL}\r
+};\r
+\r
+/**\r
+ Parses the Processor Error Node structure along with its resource\r
+ specific data.\r
+\r
+ @param [in] Ptr Pointer to the start of the Processor node.\r
+ @param [in] Length Maximum length of the Processor node.\r
+**/\r
+STATIC\r
+VOID\r
+DumpProcessorNode (\r
+ IN UINT8* Ptr,\r
+ IN UINT32 Length\r
+ )\r
+{\r
+ UINT32 Offset;\r
+\r
+ Offset = ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "Processor",\r
+ Ptr,\r
+ Length,\r
+ PARSER_PARAMS (AestProcessorStructure)\r
+ );\r
+\r
+ // Check if the values used to control the parsing logic have been\r
+ // successfully read.\r
+ if ((ProcessorId == NULL) ||\r
+ (ProcessorResourceType == NULL) ||\r
+ (ProcessorFlags == NULL)) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Insufficient Processor Error Node length. Length = %d.\n",\r
+ Length\r
+ );\r
+ return;\r
+ }\r
+\r
+ switch (*ProcessorResourceType) {\r
+ case EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_CACHE:\r
+ ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "Cache Resource",\r
+ Ptr + Offset,\r
+ Length - Offset,\r
+ PARSER_PARAMS (AestProcessorCacheResourceSubstructure)\r
+ );\r
+ break;\r
+ case EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_TLB:\r
+ ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "TLB Resource",\r
+ Ptr + Offset,\r
+ Length - Offset,\r
+ PARSER_PARAMS (AestProcessorTlbResourceSubstructure)\r
+ );\r
+ break;\r
+ case EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_GENERIC:\r
+ ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "Generic Resource",\r
+ Ptr + Offset,\r
+ Length - Offset,\r
+ PARSER_PARAMS (AestProcessorGenericResourceSubstructure)\r
+ );\r
+ break;\r
+ default:\r
+ IncrementErrorCount ();\r
+ Print (L"ERROR: Invalid Processor Resource Type.");\r
+ return;\r
+ } // switch\r
+}\r
+\r
+/**\r
+ Parses the Memory Controller node.\r
+\r
+ @param [in] Ptr Pointer to the start of the Memory Controller node.\r
+ @param [in] Length Maximum length of the Memory Controller node.\r
+**/\r
+STATIC\r
+VOID\r
+DumpMemoryControllerNode (\r
+ IN UINT8* Ptr,\r
+ IN UINT32 Length\r
+ )\r
+{\r
+ ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "Memory Controller",\r
+ Ptr,\r
+ Length,\r
+ PARSER_PARAMS (AestMemoryControllerStructure)\r
+ );\r
+}\r
+\r
+/**\r
+ Parses the SMMU node.\r
+\r
+ @param [in] Ptr Pointer to the start of the SMMU node.\r
+ @param [in] Length Maximum length of the SMMU node.\r
+**/\r
+STATIC\r
+VOID\r
+DumpSmmuNode (\r
+ IN UINT8* Ptr,\r
+ IN UINT32 Length\r
+ )\r
+{\r
+ ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "SMMU",\r
+ Ptr,\r
+ Length,\r
+ PARSER_PARAMS (AestSmmuStructure)\r
+ );\r
+}\r
+\r
+/**\r
+ Parses the Vendor-defined structure.\r
+\r
+ @param [in] Ptr Pointer to the start of the Vendor-defined node.\r
+ @param [in] Length Maximum length of the Vendor-defined node.\r
+**/\r
+STATIC\r
+VOID\r
+DumpVendorDefinedNode (\r
+ IN UINT8* Ptr,\r
+ IN UINT32 Length\r
+ )\r
+{\r
+ ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "Vendor-defined",\r
+ Ptr,\r
+ Length,\r
+ PARSER_PARAMS (AestVendorDefinedStructure)\r
+ );\r
+}\r
+\r
+/**\r
+ Parses the GIC node.\r
+\r
+ @param [in] Ptr Pointer to the start of the GIC node.\r
+ @param [in] Length Maximum length of the GIC node.\r
+**/\r
+STATIC\r
+VOID\r
+DumpGicNode (\r
+ IN UINT8* Ptr,\r
+ IN UINT32 Length\r
+ )\r
+{\r
+ ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "GIC",\r
+ Ptr,\r
+ Length,\r
+ PARSER_PARAMS (AestGicStructure)\r
+ );\r
+}\r
+\r
+/**\r
+ Parses the Node Interface structure.\r
+\r
+ @param [in] Ptr Pointer to the start of the Node Interface Structure.\r
+ @param [in] Length Maximum length of the Node Interface Structure.\r
+**/\r
+STATIC\r
+VOID\r
+DumpNodeInterface (\r
+ IN UINT8* Ptr,\r
+ IN UINT32 Length\r
+ )\r
+{\r
+ ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "Node Interface",\r
+ Ptr,\r
+ Length,\r
+ PARSER_PARAMS (AestNodeInterface)\r
+ );\r
+}\r
+\r
+/**\r
+ Parses the Node Interrupts Structure.\r
+\r
+ @param [in] Ptr Pointer to the start of the Node Interrupt array.\r
+ @param [in] Length Maximum length of the Node Interrupt array.\r
+ @param [in] InterruptCount Number if interrupts in the Node Interrupts array.\r
+**/\r
+STATIC\r
+VOID\r
+DumpNodeInterrupts (\r
+ IN UINT8* Ptr,\r
+ IN UINT32 Length,\r
+ IN UINT32 InterruptCount\r
+ )\r
+{\r
+ UINT32 Offset;\r
+ UINT32 Index;\r
+ CHAR8 Buffer[64];\r
+\r
+ if (Length < (InterruptCount * sizeof (EFI_ACPI_AEST_INTERRUPT_STRUCT))) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Node not long enough for Interrupt Array.\n"\\r
+ L" Length left = %d, Required = %d, Interrupt Count = %d\n",\r
+ Length,\r
+ (InterruptCount * sizeof (EFI_ACPI_AEST_INTERRUPT_STRUCT)),\r
+ InterruptCount\r
+ );\r
+ return;\r
+ }\r
+\r
+ Offset = 0;\r
+ for (Index = 0; Index < InterruptCount; Index++) {\r
+ AsciiSPrint (\r
+ Buffer,\r
+ sizeof (Buffer),\r
+ "Node Interrupt [%d]",\r
+ Index\r
+ );\r
+\r
+ Offset += ParseAcpi (\r
+ TRUE,\r
+ 4,\r
+ Buffer,\r
+ Ptr + Offset,\r
+ Length - Offset,\r
+ PARSER_PARAMS (AestNodeInterrupt)\r
+ );\r
+ } //for\r
+}\r
+\r
+/**\r
+ Parses a single AEST Node Structure.\r
+\r
+ @param [in] Ptr Pointer to the start of the Node.\r
+ @param [in] Length Maximum length of the Node.\r
+ @param [in] NodeType AEST node type.\r
+ @param [in] DataOffset Offset to the node data.\r
+ @param [in] InterfaceOffset Offset to the node interface data.\r
+ @param [in] InterruptArrayOffset Offset to the node interrupt array.\r
+ @param [in] InterruptCount Number of interrupts.\r
+**/\r
+STATIC\r
+VOID\r
+DumpAestNodeStructure (\r
+ IN UINT8* Ptr,\r
+ IN UINT32 Length,\r
+ IN UINT8 NodeType,\r
+ IN UINT32 DataOffset,\r
+ IN UINT32 InterfaceOffset,\r
+ IN UINT32 InterruptArrayOffset,\r
+ IN UINT32 InterruptCount\r
+ )\r
+{\r
+ UINT32 Offset;\r
+ UINT32 RemainingLength;\r
+ UINT8* NodeDataPtr;\r
+\r
+ Offset = ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "Node Structure",\r
+ Ptr,\r
+ Length,\r
+ PARSER_PARAMS (AestNodeHeaderParser)\r
+ );\r
+\r
+ if ((Offset > DataOffset) || (DataOffset > Length)) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Invalid Node Data Offset: %d.\n"\\r
+ L" It should be between %d and %d.\n",\r
+ DataOffset,\r
+ Offset,\r
+ Length\r
+ );\r
+ }\r
+\r
+ if ((Offset > InterfaceOffset) || (InterfaceOffset > Length)) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Invalid Node Interface Offset: %d.\n"\\r
+ L" It should be between %d and %d.\n",\r
+ InterfaceOffset,\r
+ Offset,\r
+ Length\r
+ );\r
+ }\r
+\r
+ if ((Offset > InterruptArrayOffset) || (InterruptArrayOffset > Length)) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Invalid Node Interrupt Array Offset: %d.\n"\\r
+ L" It should be between %d and %d.\n",\r
+ InterruptArrayOffset,\r
+ Offset,\r
+ Length\r
+ );\r
+ }\r
+\r
+ // Parse Node Data Field.\r
+ NodeDataPtr = Ptr + DataOffset;\r
+ RemainingLength = Length - DataOffset;\r
+ switch (NodeType) {\r
+ case EFI_ACPI_AEST_NODE_TYPE_PROCESSOR:\r
+ DumpProcessorNode (NodeDataPtr, RemainingLength);\r
+ break;\r
+ case EFI_ACPI_AEST_NODE_TYPE_MEMORY:\r
+ DumpMemoryControllerNode (NodeDataPtr, RemainingLength);\r
+ break;\r
+ case EFI_ACPI_AEST_NODE_TYPE_SMMU:\r
+ DumpSmmuNode (NodeDataPtr, RemainingLength);\r
+ break;\r
+ case EFI_ACPI_AEST_NODE_TYPE_VENDOR_DEFINED:\r
+ DumpVendorDefinedNode (NodeDataPtr, RemainingLength);\r
+ break;\r
+ case EFI_ACPI_AEST_NODE_TYPE_GIC:\r
+ DumpGicNode (NodeDataPtr, RemainingLength);\r
+ break;\r
+ default:\r
+ IncrementErrorCount ();\r
+ Print (L"ERROR: Invalid Error Node Type.\n");\r
+ return;\r
+ } // switch\r
+\r
+ // Parse the Interface Field.\r
+ DumpNodeInterface (\r
+ Ptr + InterfaceOffset,\r
+ Length - InterfaceOffset\r
+ );\r
+\r
+ // Parse the Node Interrupt Array.\r
+ DumpNodeInterrupts (\r
+ Ptr + InterruptArrayOffset,\r
+ Length - InterruptArrayOffset,\r
+ InterruptCount\r
+ );\r
+\r
+ return;\r
+}\r
+\r
+/**\r
+ This function parses the ACPI AEST table.\r
+ When trace is enabled this function parses the AEST table and\r
+ traces the ACPI table fields.\r
+\r
+ This function also performs validation of the ACPI table fields.\r
+\r
+ @param [in] Trace If TRUE, trace the ACPI fields.\r
+ @param [in] Ptr Pointer to the start of the buffer.\r
+ @param [in] AcpiTableLength Length of the ACPI table.\r
+ @param [in] AcpiTableRevision Revision of the ACPI table.\r
+**/\r
+VOID\r
+EFIAPI\r
+ParseAcpiAest (\r
+ IN BOOLEAN Trace,\r
+ IN UINT8* Ptr,\r
+ IN UINT32 AcpiTableLength,\r
+ IN UINT8 AcpiTableRevision\r
+ )\r
+{\r
+ UINT32 Offset;\r
+ UINT8* NodePtr;\r
+\r
+ if (!Trace) {\r
+ return;\r
+ }\r
+\r
+ Offset = ParseAcpi (\r
+ TRUE,\r
+ 0,\r
+ "AEST",\r
+ Ptr,\r
+ AcpiTableLength,\r
+ PARSER_PARAMS (AestParser)\r
+ );\r
+\r
+ while (Offset < AcpiTableLength) {\r
+ NodePtr = Ptr + Offset;\r
+\r
+ ParseAcpi (\r
+ FALSE,\r
+ 0,\r
+ NULL,\r
+ NodePtr,\r
+ AcpiTableLength - Offset,\r
+ PARSER_PARAMS (AestNodeHeaderParser)\r
+ );\r
+\r
+ // Check if the values used to control the parsing logic have been\r
+ // successfully read.\r
+ if ((AestNodeType == NULL) ||\r
+ (AestNodeLength == NULL) ||\r
+ (NodeDataOffset == NULL) ||\r
+ (NodeInterfaceOffset == NULL) ||\r
+ (NodeInterruptArrayOffset == NULL) ||\r
+ (NodeInterruptCount == NULL)) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Insufficient length left for Node Structure.\n"\\r
+ L" Length left = %d.\n",\r
+ AcpiTableLength - Offset\r
+ );\r
+ return;\r
+ }\r
+\r
+ // Validate AEST Node length\r
+ if ((*AestNodeLength == 0) ||\r
+ ((Offset + (*AestNodeLength)) > AcpiTableLength)) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Invalid AEST Node length. " \\r
+ L"Length = %d. Offset = %d. AcpiTableLength = %d.\n",\r
+ *AestNodeLength,\r
+ Offset,\r
+ AcpiTableLength\r
+ );\r
+ return;\r
+ }\r
+\r
+ DumpAestNodeStructure (\r
+ NodePtr,\r
+ *AestNodeLength,\r
+ *AestNodeType,\r
+ *NodeDataOffset,\r
+ *NodeInterfaceOffset,\r
+ *NodeInterruptArrayOffset,\r
+ *NodeInterruptCount\r
+ );\r
+\r
+ Offset += *AestNodeLength;\r
+ } // while\r
+}\r