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