diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c | 764 |
1 files changed, 764 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c new file mode 100644 index 00000000..1cd8b4f4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c @@ -0,0 +1,764 @@ +/** @file + IORT table parser + + Copyright (c) 2016 - 2020, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - IO Remapping Table, Platform Design Document, Revision D, March 2018 +**/ + +#include <IndustryStandard/IoRemappingTable.h> +#include <Library/PrintLib.h> +#include <Library/UefiLib.h> +#include "AcpiParser.h" +#include "AcpiTableParser.h" +#include "AcpiViewConfig.h" + +// Local variables +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; + +STATIC CONST UINT32* IortNodeCount; +STATIC CONST UINT32* IortNodeOffset; + +STATIC CONST UINT8* IortNodeType; +STATIC CONST UINT16* IortNodeLength; +STATIC CONST UINT32* IortIdMappingCount; +STATIC CONST UINT32* IortIdMappingOffset; + +STATIC CONST UINT32* InterruptContextCount; +STATIC CONST UINT32* InterruptContextOffset; +STATIC CONST UINT32* PmuInterruptCount; +STATIC CONST UINT32* PmuInterruptOffset; + +STATIC CONST UINT32* ItsCount; + +/** + This function validates the ID Mapping array count for the ITS node. + + @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 +ValidateItsIdMappingCount ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + if (*(UINT32*)Ptr != 0) { + IncrementErrorCount (); + Print (L"\nERROR: IORT ID Mapping count must be zero."); + } +} + +/** + This function validates the ID Mapping array count for the Performance + Monitoring Counter Group (PMCG) node. + + @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 +ValidatePmcgIdMappingCount ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + if (*(UINT32*)Ptr > 1) { + IncrementErrorCount (); + Print (L"\nERROR: IORT ID Mapping count must not be greater than 1."); + } +} + +/** + This function validates the ID Mapping array offset for the ITS node. + + @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 +ValidateItsIdArrayReference ( + IN UINT8* Ptr, + IN VOID* Context + ) +{ + if (*(UINT32*)Ptr != 0) { + IncrementErrorCount (); + Print (L"\nERROR: IORT ID Mapping offset must be zero."); + } +} + +/** + Helper Macro for populating the IORT Node header in the ACPI_PARSER array. + + @param [out] ValidateIdMappingCount Optional pointer to a function for + validating the ID Mapping count. + @param [out] ValidateIdArrayReference Optional pointer to a function for + validating the ID Array reference. +**/ +#define PARSE_IORT_NODE_HEADER(ValidateIdMappingCount, \ + ValidateIdArrayReference) \ + { L"Type", 1, 0, L"%d", NULL, (VOID**)&IortNodeType, NULL, NULL }, \ + { L"Length", 2, 1, L"%d", NULL, (VOID**)&IortNodeLength, NULL, NULL }, \ + { L"Revision", 1, 3, L"%d", NULL, NULL, NULL, NULL }, \ + { L"Reserved", 4, 4, L"0x%x", NULL, NULL, NULL, NULL }, \ + { L"Number of ID mappings", 4, 8, L"%d", NULL, \ + (VOID**)&IortIdMappingCount, ValidateIdMappingCount, NULL }, \ + { L"Reference to ID Array", 4, 12, L"0x%x", NULL, \ + (VOID**)&IortIdMappingOffset, ValidateIdArrayReference, NULL } + +/** + An ACPI_PARSER array describing the ACPI IORT Table +**/ +STATIC CONST ACPI_PARSER IortParser[] = { + PARSE_ACPI_HEADER (&AcpiHdrInfo), + {L"Number of IORT Nodes", 4, 36, L"%d", NULL, + (VOID**)&IortNodeCount, NULL, NULL}, + {L"Offset to Array of IORT Nodes", 4, 40, L"0x%x", NULL, + (VOID**)&IortNodeOffset, NULL, NULL}, + {L"Reserved", 4, 44, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the IORT node header structure. +**/ +STATIC CONST ACPI_PARSER IortNodeHeaderParser[] = { + PARSE_IORT_NODE_HEADER (NULL, NULL) +}; + +/** + An ACPI_PARSER array describing the IORT SMMUv1/2 node. +**/ +STATIC CONST ACPI_PARSER IortNodeSmmuV1V2Parser[] = { + PARSE_IORT_NODE_HEADER (NULL, NULL), + {L"Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Span", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Model", 4, 32, L"%d", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 36, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reference to Global Interrupt Array", 4, 40, L"0x%x", NULL, NULL, NULL, + NULL}, + {L"Number of context interrupts", 4, 44, L"%d", NULL, + (VOID**)&InterruptContextCount, NULL, NULL}, + {L"Reference to Context Interrupt Array", 4, 48, L"0x%x", NULL, + (VOID**)&InterruptContextOffset, NULL, NULL}, + {L"Number of PMU Interrupts", 4, 52, L"%d", NULL, + (VOID**)&PmuInterruptCount, NULL, NULL}, + {L"Reference to PMU Interrupt Array", 4, 56, L"0x%x", NULL, + (VOID**)&PmuInterruptOffset, NULL, NULL}, + + // Interrupt Array + {L"SMMU_NSgIrpt", 4, 60, L"0x%x", NULL, NULL, NULL, NULL}, + {L"SMMU_NSgIrpt interrupt flags", 4, 64, L"0x%x", NULL, NULL, NULL, NULL}, + {L"SMMU_NSgCfgIrpt", 4, 68, L"0x%x", NULL, NULL, NULL, NULL}, + {L"SMMU_NSgCfgIrpt interrupt flags", 4, 72, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the SMMUv1/2 Node Interrupt Array. +**/ +STATIC CONST ACPI_PARSER InterruptArrayParser[] = { + {L"Interrupt GSIV", 4, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the IORT ID Mapping. +**/ +STATIC CONST ACPI_PARSER IortNodeIdMappingParser[] = { + {L"Input base", 4, 0, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Number of IDs", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Output base", 4, 8, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Output reference", 4, 12, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 16, L"0x%x", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the IORT SMMUv3 node. +**/ +STATIC CONST ACPI_PARSER IortNodeSmmuV3Parser[] = { + PARSE_IORT_NODE_HEADER (NULL, NULL), + {L"Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Flags", 4, 24, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 4, 28, L"0x%x", NULL, NULL, NULL, NULL}, + {L"VATOS Address", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Model", 4, 40, L"%d", NULL, NULL, NULL, NULL}, + {L"Event", 4, 44, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PRI", 4, 48, L"0x%x", NULL, NULL, NULL, NULL}, + {L"GERR", 4, 52, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Sync", 4, 56, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Proximity domain", 4, 60, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Device ID mapping index", 4, 64, L"%d", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the IORT ITS node. +**/ +STATIC CONST ACPI_PARSER IortNodeItsParser[] = { + PARSE_IORT_NODE_HEADER ( + ValidateItsIdMappingCount, + ValidateItsIdArrayReference + ), + {L"Number of ITSs", 4, 16, L"%d", NULL, (VOID**)&ItsCount, NULL} +}; + +/** + An ACPI_PARSER array describing the ITS ID. +**/ +STATIC CONST ACPI_PARSER ItsIdParser[] = { + { L"GIC ITS Identifier", 4, 0, L"%d", NULL, NULL, NULL } +}; + +/** + An ACPI_PARSER array describing the IORT Names Component node. +**/ +STATIC CONST ACPI_PARSER IortNodeNamedComponentParser[] = { + PARSE_IORT_NODE_HEADER (NULL, NULL), + {L"Node Flags", 4, 16, L"%d", NULL, NULL, NULL, NULL}, + {L"Memory access properties", 8, 20, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Device memory address size limit", 1, 28, L"%d", NULL, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the IORT Root Complex node. +**/ +STATIC CONST ACPI_PARSER IortNodeRootComplexParser[] = { + PARSE_IORT_NODE_HEADER (NULL, NULL), + {L"Memory access properties", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"ATS Attribute", 4, 24, L"0x%x", NULL, NULL, NULL, NULL}, + {L"PCI Segment number", 4, 28, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Memory access size limit", 1, 32, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Reserved", 3, 33, L"%x %x %x", Dump3Chars, NULL, NULL, NULL} +}; + +/** + An ACPI_PARSER array describing the IORT PMCG node. +**/ +STATIC CONST ACPI_PARSER IortNodePmcgParser[] = { + PARSE_IORT_NODE_HEADER (ValidatePmcgIdMappingCount, NULL), + {L"Page 0 Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL}, + {L"Overflow interrupt GSIV", 4, 24, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Node reference", 4, 28, L"0x%x", NULL, NULL, NULL, NULL}, + {L"Page 1 Base Address", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL} +}; + +/** + This function parses the IORT Node Id Mapping array. + + @param [in] Ptr Pointer to the start of the ID mapping array. + @param [in] Length Length of the buffer. + @param [in] MappingCount The ID Mapping count. +**/ +STATIC +VOID +DumpIortNodeIdMappings ( + IN UINT8* Ptr, + IN UINT32 Length, + IN UINT32 MappingCount + ) +{ + UINT32 Index; + UINT32 Offset; + CHAR8 Buffer[40]; // Used for AsciiName param of ParseAcpi + + Index = 0; + Offset = 0; + + while ((Index < MappingCount) && + (Offset < Length)) { + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "ID Mapping [%d]", + Index + ); + Offset += ParseAcpi ( + TRUE, + 4, + Buffer, + Ptr + Offset, + Length - Offset, + PARSER_PARAMS (IortNodeIdMappingParser) + ); + Index++; + } +} + +/** + This function parses the IORT SMMUv1/2 node. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the buffer. + @param [in] MappingCount The ID Mapping count. + @param [in] MappingOffset The offset of the ID Mapping array + from the start of the IORT table. +**/ +STATIC +VOID +DumpIortNodeSmmuV1V2 ( + IN UINT8* Ptr, + IN UINT16 Length, + IN UINT32 MappingCount, + IN UINT32 MappingOffset + ) +{ + UINT32 Index; + UINT32 Offset; + CHAR8 Buffer[50]; // Used for AsciiName param of ParseAcpi + + ParseAcpi ( + TRUE, + 2, + "SMMUv1 or SMMUv2 Node", + Ptr, + Length, + PARSER_PARAMS (IortNodeSmmuV1V2Parser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((InterruptContextCount == NULL) || + (InterruptContextOffset == NULL) || + (PmuInterruptCount == NULL) || + (PmuInterruptOffset == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient SMMUv1/2 node length. Length = %d\n", + Length + ); + return; + } + + Offset = *InterruptContextOffset; + Index = 0; + + while ((Index < *InterruptContextCount) && + (Offset < Length)) { + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "Context Interrupts Array [%d]", + Index + ); + Offset += ParseAcpi ( + TRUE, + 4, + Buffer, + Ptr + Offset, + Length - Offset, + PARSER_PARAMS (InterruptArrayParser) + ); + Index++; + } + + Offset = *PmuInterruptOffset; + Index = 0; + + while ((Index < *PmuInterruptCount) && + (Offset < Length)) { + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "PMU Interrupts Array [%d]", + Index + ); + Offset += ParseAcpi ( + TRUE, + 4, + Buffer, + Ptr + Offset, + Length - Offset, + PARSER_PARAMS (InterruptArrayParser) + ); + Index++; + } + + DumpIortNodeIdMappings ( + Ptr + MappingOffset, + Length - MappingOffset, + MappingCount + ); +} + +/** + This function parses the IORT SMMUv3 node. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the buffer. + @param [in] MappingCount The ID Mapping count. + @param [in] MappingOffset The offset of the ID Mapping array + from the start of the IORT table. +**/ +STATIC +VOID +DumpIortNodeSmmuV3 ( + IN UINT8* Ptr, + IN UINT16 Length, + IN UINT32 MappingCount, + IN UINT32 MappingOffset + ) +{ + ParseAcpi ( + TRUE, + 2, + "SMMUV3 Node", + Ptr, + Length, + PARSER_PARAMS (IortNodeSmmuV3Parser) + ); + + DumpIortNodeIdMappings ( + Ptr + MappingOffset, + Length - MappingOffset, + MappingCount + ); +} + +/** + This function parses the IORT ITS node. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the buffer. +**/ +STATIC +VOID +DumpIortNodeIts ( + IN UINT8* Ptr, + IN UINT16 Length + ) +{ + UINT32 Offset; + UINT32 Index; + CHAR8 Buffer[80]; // Used for AsciiName param of ParseAcpi + + Offset = ParseAcpi ( + TRUE, + 2, + "ITS Node", + Ptr, + Length, + PARSER_PARAMS (IortNodeItsParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if (ItsCount == NULL) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient ITS group length. Length = %d.\n", + Length + ); + return; + } + + Index = 0; + + while ((Index < *ItsCount) && + (Offset < Length)) { + AsciiSPrint ( + Buffer, + sizeof (Buffer), + "GIC ITS Identifier Array [%d]", + Index + ); + Offset += ParseAcpi ( + TRUE, + 4, + Buffer, + Ptr + Offset, + Length - Offset, + PARSER_PARAMS (ItsIdParser) + ); + Index++; + } + + // Note: ITS does not have the ID Mappings Array + +} + +/** + This function parses the IORT Named Component node. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the buffer. + @param [in] MappingCount The ID Mapping count. + @param [in] MappingOffset The offset of the ID Mapping array + from the start of the IORT table. +**/ +STATIC +VOID +DumpIortNodeNamedComponent ( + IN UINT8* Ptr, + IN UINT16 Length, + IN UINT32 MappingCount, + IN UINT32 MappingOffset + ) +{ + UINT32 Offset; + + Offset = ParseAcpi ( + TRUE, + 2, + "Named Component Node", + Ptr, + Length, + PARSER_PARAMS (IortNodeNamedComponentParser) + ); + + // Estimate the Device Name length + PrintFieldName (2, L"Device Object Name"); + + while ((*(Ptr + Offset) != 0) && + (Offset < Length)) { + Print (L"%c", *(Ptr + Offset)); + Offset++; + } + Print (L"\n"); + + DumpIortNodeIdMappings ( + Ptr + MappingOffset, + Length - MappingOffset, + MappingCount + ); +} + +/** + This function parses the IORT Root Complex node. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the buffer. + @param [in] MappingCount The ID Mapping count. + @param [in] MappingOffset The offset of the ID Mapping array + from the start of the IORT table. +**/ +STATIC +VOID +DumpIortNodeRootComplex ( + IN UINT8* Ptr, + IN UINT16 Length, + IN UINT32 MappingCount, + IN UINT32 MappingOffset + ) +{ + ParseAcpi ( + TRUE, + 2, + "Root Complex Node", + Ptr, + Length, + PARSER_PARAMS (IortNodeRootComplexParser) + ); + + DumpIortNodeIdMappings ( + Ptr + MappingOffset, + Length - MappingOffset, + MappingCount + ); +} + +/** + This function parses the IORT PMCG node. + + @param [in] Ptr Pointer to the start of the buffer. + @param [in] Length Length of the buffer. + @param [in] MappingCount The ID Mapping count. + @param [in] MappingOffset The offset of the ID Mapping array + from the start of the IORT table. +**/ +STATIC +VOID +DumpIortNodePmcg ( + IN UINT8* Ptr, + IN UINT16 Length, + IN UINT32 MappingCount, + IN UINT32 MappingOffset +) +{ + ParseAcpi ( + TRUE, + 2, + "PMCG Node", + Ptr, + Length, + PARSER_PARAMS (IortNodePmcgParser) + ); + + DumpIortNodeIdMappings ( + Ptr + MappingOffset, + Length - MappingOffset, + MappingCount + ); +} + +/** + This function parses the ACPI IORT table. + When trace is enabled this function parses the IORT table and traces the ACPI fields. + + This function also parses the following nodes: + - ITS Group + - Named Component + - Root Complex + - SMMUv1/2 + - SMMUv3 + - PMCG + + 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 +ParseAcpiIort ( + IN BOOLEAN Trace, + IN UINT8* Ptr, + IN UINT32 AcpiTableLength, + IN UINT8 AcpiTableRevision + ) +{ + UINT32 Offset; + UINT32 Index; + UINT8* NodePtr; + + if (!Trace) { + return; + } + + ParseAcpi ( + TRUE, + 0, + "IORT", + Ptr, + AcpiTableLength, + PARSER_PARAMS (IortParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((IortNodeCount == NULL) || + (IortNodeOffset == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient table length. AcpiTableLength = %d.\n", + AcpiTableLength + ); + return; + } + + Offset = *IortNodeOffset; + NodePtr = Ptr + Offset; + Index = 0; + + // Parse the specified number of IORT nodes or the IORT table buffer length. + // Whichever is minimum. + while ((Index++ < *IortNodeCount) && + (Offset < AcpiTableLength)) { + // Parse the IORT Node Header + ParseAcpi ( + FALSE, + 0, + "IORT Node Header", + NodePtr, + AcpiTableLength - Offset, + PARSER_PARAMS (IortNodeHeaderParser) + ); + + // Check if the values used to control the parsing logic have been + // successfully read. + if ((IortNodeType == NULL) || + (IortNodeLength == NULL) || + (IortIdMappingCount == NULL) || + (IortIdMappingOffset == NULL)) { + IncrementErrorCount (); + Print ( + L"ERROR: Insufficient remaining table buffer length to read the " \ + L"IORT node header. Length = %d.\n", + AcpiTableLength - Offset + ); + return; + } + + // Validate IORT Node length + if ((*IortNodeLength == 0) || + ((Offset + (*IortNodeLength)) > AcpiTableLength)) { + IncrementErrorCount (); + Print ( + L"ERROR: Invalid IORT Node length. " \ + L"Length = %d. Offset = %d. AcpiTableLength = %d.\n", + *IortNodeLength, + Offset, + AcpiTableLength + ); + return; + } + + PrintFieldName (2, L"* Node Offset *"); + Print (L"0x%x\n", Offset); + + switch (*IortNodeType) { + case EFI_ACPI_IORT_TYPE_ITS_GROUP: + DumpIortNodeIts ( + NodePtr, + *IortNodeLength + ); + break; + case EFI_ACPI_IORT_TYPE_NAMED_COMP: + DumpIortNodeNamedComponent ( + NodePtr, + *IortNodeLength, + *IortIdMappingCount, + *IortIdMappingOffset + ); + break; + case EFI_ACPI_IORT_TYPE_ROOT_COMPLEX: + DumpIortNodeRootComplex ( + NodePtr, + *IortNodeLength, + *IortIdMappingCount, + *IortIdMappingOffset + ); + break; + case EFI_ACPI_IORT_TYPE_SMMUv1v2: + DumpIortNodeSmmuV1V2 ( + NodePtr, + *IortNodeLength, + *IortIdMappingCount, + *IortIdMappingOffset + ); + break; + case EFI_ACPI_IORT_TYPE_SMMUv3: + DumpIortNodeSmmuV3 ( + NodePtr, + *IortNodeLength, + *IortIdMappingCount, + *IortIdMappingOffset + ); + break; + case EFI_ACPI_IORT_TYPE_PMCG: + DumpIortNodePmcg ( + NodePtr, + *IortNodeLength, + *IortIdMappingCount, + *IortIdMappingOffset + ); + break; + + default: + IncrementErrorCount (); + Print (L"ERROR: Unsupported IORT Node type = %d\n", *IortNodeType); + } // switch + + NodePtr += (*IortNodeLength); + Offset += (*IortNodeLength); + } // while +} |