]> git.proxmox.com Git - mirror_edk2.git/commitdiff
ShellPkg/Acpiview: AEST Parser
authorMarc Moisson-Franckhauser <marc.moisson-franckhauser@arm.com>
Tue, 3 Nov 2020 14:32:02 +0000 (22:32 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Fri, 8 Jan 2021 03:50:34 +0000 (03:50 +0000)
Bugzilla: 3048 (https://bugzilla.tianocore.org/show_bug.cgi?id=3048)

Add a new parser for the Arm Error Source Table (AEST) described in
the ACPI for the Armv8 RAS Extensions 1.1 Platform Design Document,
dated 28 September 2020.
(https://developer.arm.com/documentation/den0085/0101/)

AEST enables kernel-first handling of errors in a system that supports
the Armv8 RAS extensions. It covers Armv8.2+ RAS extensions for PEs
and the RAS system architecture for non-PE system components.

Signed-off-by: Marc Moisson-Franckhauser <marc.moisson-franckhauser@arm.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
Reviewed-by: Zhichao Gao <zhichao.gao@intel.com>
ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h
ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Aest/AestParser.c [new file with mode: 0644]
ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c
ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf
ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.uni

index 051fdf807abb1067a264c136364bb6d145b38dab..a37b62bc7e34a0660814f8d176088282c7d52df5 100644 (file)
@@ -461,6 +461,27 @@ ParseAcpiHeader (
   OUT CONST UINT8**  Revision\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
 /**\r
   This function parses the ACPI BGRT table.\r
   When trace is enabled this function parses the BGRT table and\r
diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Aest/AestParser.c b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Aest/AestParser.c
new file mode 100644 (file)
index 0000000..7aa8c8f
--- /dev/null
@@ -0,0 +1,755 @@
+/** @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
index feb80661cddc420670edb2d8c7a570b0a89272d8..90e8741175c5b4096409503741291cc34dd57789 100644 (file)
@@ -7,6 +7,7 @@
 \r
 #include <Guid/ShellLibHiiGuid.h>\r
 #include <IndustryStandard/Acpi.h>\r
+#include <IndustryStandard/ArmErrorSourceTable.h>\r
 \r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/HiiLib.h>\r
@@ -46,6 +47,7 @@ STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
 STATIC\r
 CONST\r
 ACPI_TABLE_PARSER ParserList[] = {\r
+  {EFI_ACPI_6_3_ARM_ERROR_SOURCE_TABLE_SIGNATURE, ParseAcpiAest},\r
   {EFI_ACPI_6_2_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE, ParseAcpiBgrt},\r
   {EFI_ACPI_6_2_DEBUG_PORT_2_TABLE_SIGNATURE, ParseAcpiDbg2},\r
   {EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,\r
index efa9c8784a6670e5a4f500e0ae559a4938852f95..947fb1f375667e12f8603e4264fef5e69cb98919 100644 (file)
@@ -27,6 +27,7 @@
   AcpiView.h\r
   AcpiViewConfig.c\r
   AcpiViewConfig.h\r
+  Parsers/Aest/AestParser.c\r
   Parsers/Bgrt/BgrtParser.c\r
   Parsers/Dbg2/Dbg2Parser.c\r
   Parsers/Dsdt/DsdtParser.c\r
index 7cd43d0518fd0a23dc547a5cab0d08b62602a113..9dbffcd7c534fa9039668cfbe79f75d3a94c9b28 100644 (file)
@@ -1,6 +1,6 @@
 // /**\r
 //\r
-// Copyright (c) 2016 - 2020, ARM Limited. All rights reserved.<BR>\r
+// Copyright (c) 2016 - 2020, Arm Limited. All rights reserved.<BR>\r
 // SPDX-License-Identifier: BSD-2-Clause-Patent\r
 //\r
 // Module Name:\r
@@ -78,6 +78,7 @@
 "     other than AcpiTable header. The actual header can refer to the ACPI spec\r\n"\r
 "     6.2\r\n"\r
 "     Extra A. Particular types:\r\n"\r
+"       AEST  - Arm Error Source Table\r\n"\r
 "       APIC  - Multiple APIC Description Table (MADT)\r\n"\r
 "       BGRT  - Boot Graphics Resource Table\r\n"\r
 "       DBG2  - Debug Port Table 2\r\n"\r