| /** @file | |
| IORT table parser | |
| Copyright (c) 2016 - 2024, Arm Limited. All rights reserved. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| @par Reference(s): | |
| - IO Remapping Table, Platform Design Document, Revision E.d, Feb 2022 | |
| (https://developer.arm.com/documentation/den0049/) | |
| @par Glossary: | |
| - Ref - Reference | |
| - Desc - Descriptor | |
| **/ | |
| #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 UINT8 *IortNodeRevision; | |
| 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; | |
| STATIC CONST UINT32 *RmrMemDescCount; | |
| STATIC CONST UINT32 *RmrMemDescOffset; | |
| /** | |
| 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] Length Length of the field. | |
| @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 UINT32 Length, | |
| 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] Length Length of the field. | |
| @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 UINT32 Length, | |
| 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] Length Length of the field. | |
| @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 UINT32 Length, | |
| IN VOID *Context | |
| ) | |
| { | |
| if (*(UINT32 *)Ptr != 0) { | |
| IncrementErrorCount (); | |
| Print (L"\nERROR: IORT ID Mapping offset must be zero."); | |
| } | |
| } | |
| /** | |
| This function validates that the Physical Range address or length is not zero | |
| and is 64K aligned. | |
| @param [in] Ptr Pointer to the start of the field data. | |
| @param [in] Length Length of the field. | |
| @param [in] Context Pointer to context specific information e.g. this | |
| could be a pointer to the ACPI table header. | |
| **/ | |
| STATIC | |
| VOID | |
| EFIAPI | |
| ValidatePhysicalRange ( | |
| IN UINT8 *Ptr, | |
| IN UINT32 Length, | |
| IN VOID *Context | |
| ) | |
| { | |
| UINT64 Value; | |
| Value = *(UINT64 *)Ptr; | |
| if ((Value == 0) || ((Value & (SIZE_64KB - 1)) != 0)) { | |
| IncrementErrorCount (); | |
| Print (L"\nERROR: Physical Range must be 64K aligned and cannot be zero."); | |
| } | |
| } | |
| /** | |
| This function validates that the RMR memory range descriptor count. | |
| @param [in] Ptr Pointer to the start of the field data. | |
| @param [in] Length Length of the field. | |
| @param [in] Context Pointer to context specific information e.g. this | |
| could be a pointer to the ACPI table header. | |
| **/ | |
| STATIC | |
| VOID | |
| EFIAPI | |
| ValidateRmrMemDescCount ( | |
| IN UINT8 *Ptr, | |
| IN UINT32 Length, | |
| IN VOID *Context | |
| ) | |
| { | |
| if (*(UINT32 *)Ptr == 0) { | |
| IncrementErrorCount (); | |
| Print (L"\nERROR: Memory Range Descriptor count must be >=1."); | |
| } | |
| } | |
| /** | |
| 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, (VOID**)&IortNodeRevision, NULL, NULL }, \ | |
| { L"Identifier", 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"Global Interrupt Array Ref", 4, 40, L"0x%x", NULL, NULL, NULL, | |
| NULL }, | |
| { L"Number of context interrupts", 4, 44, L"%d", NULL, | |
| (VOID **)&InterruptContextCount, NULL, NULL }, | |
| { L"Context Interrupt Array Ref", 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"PMU Interrupt Array Ref", 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"PASID capabilities", 2, 33, L"0x%x", NULL, NULL, NULL, NULL }, | |
| { L"Reserved", 1, 35, L"%x", NULL, NULL, NULL, NULL }, | |
| { L"Flags", 4, 36, L"0x%x", NULL, 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 } | |
| }; | |
| /** | |
| An ACPI_PARSER array describing the IORT RMR node. | |
| **/ | |
| STATIC CONST ACPI_PARSER IortNodeRmrParser[] = { | |
| PARSE_IORT_NODE_HEADER (NULL, NULL), | |
| { L"Flags", 4, 16, L"0x%x", NULL, NULL, NULL, NULL }, | |
| { L"Memory Range Desc count", 4, 20, L"%d", NULL, | |
| (VOID **)&RmrMemDescCount, ValidateRmrMemDescCount,NULL }, | |
| { L"Memory Range Desc Ref", 4, 24, L"0x%x", NULL, | |
| (VOID **)&RmrMemDescOffset, NULL, NULL } | |
| }; | |
| /** | |
| An ACPI_PARSER array describing the IORT RMR Memory Range Descriptor. | |
| **/ | |
| STATIC CONST ACPI_PARSER IortNodeRmrMemRangeDescParser[] = { | |
| { L"Physical Range offset", 8, 0, L"0x%lx", NULL, NULL, ValidatePhysicalRange, | |
| NULL }, | |
| { L"Physical Range length", 8, 8, L"0x%lx", NULL, NULL, ValidatePhysicalRange, | |
| NULL }, | |
| { L"Reserved", 4, 16, L"0x%x", 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 IORT RMR Node Memory Range Descriptor array. | |
| @param [in] Ptr Pointer to the start of the Memory Range Descriptor | |
| array. | |
| @param [in] Length Length of the buffer. | |
| @param [in] DescCount Memory Range Descriptor count. | |
| **/ | |
| STATIC | |
| VOID | |
| DumpIortNodeRmrMemRangeDesc ( | |
| IN UINT8 *Ptr, | |
| IN UINT32 Length, | |
| IN UINT32 DescCount | |
| ) | |
| { | |
| UINT32 Index; | |
| UINT32 Offset; | |
| CHAR8 Buffer[40]; // Used for AsciiName param of ParseAcpi | |
| Index = 0; | |
| Offset = 0; | |
| while ((Index < DescCount) && | |
| (Offset < Length)) | |
| { | |
| AsciiSPrint ( | |
| Buffer, | |
| sizeof (Buffer), | |
| "Mem range Descriptor [%d]", | |
| Index | |
| ); | |
| Offset += ParseAcpi ( | |
| TRUE, | |
| 4, | |
| Buffer, | |
| Ptr + Offset, | |
| Length - Offset, | |
| PARSER_PARAMS (IortNodeRmrMemRangeDescParser) | |
| ); | |
| Index++; | |
| } | |
| } | |
| /** | |
| This function parses the IORT RMR 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 | |
| DumpIortNodeRmr ( | |
| IN UINT8 *Ptr, | |
| IN UINT16 Length, | |
| IN UINT32 MappingCount, | |
| IN UINT32 MappingOffset | |
| ) | |
| { | |
| ParseAcpi ( | |
| TRUE, | |
| 2, | |
| "RMR Node", | |
| Ptr, | |
| Length, | |
| PARSER_PARAMS (IortNodeRmrParser) | |
| ); | |
| if (*IortNodeRevision == EFI_ACPI_IORT_RMR_NODE_REVISION_02) { | |
| IncrementErrorCount (); | |
| Print ( | |
| L"ERROR: RMR node Rev 2 (defined in IORT Rev E.c) must not be used." | |
| L" IORT tabe Revision E.c is deprecated and must not be used.\n" | |
| ); | |
| } | |
| DumpIortNodeIdMappings ( | |
| Ptr + MappingOffset, | |
| Length - MappingOffset, | |
| MappingCount | |
| ); | |
| DumpIortNodeRmrMemRangeDesc ( | |
| Ptr + (*RmrMemDescOffset), | |
| Length - (*RmrMemDescOffset), | |
| *RmrMemDescCount | |
| ); | |
| } | |
| /** | |
| 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 | |
| - RMR | |
| 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; | |
| } | |
| if ((AcpiTableRevision > EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00) && | |
| (AcpiTableRevision < EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)) | |
| { | |
| Print ( | |
| L"ERROR: Parsing not supported for IORT tabe Revision E, E.<a,b,c>.\n" | |
| ); | |
| if (AcpiTableRevision == EFI_ACPI_IO_REMAPPING_TABLE_REVISION_04) { | |
| IncrementErrorCount (); | |
| Print ( | |
| L"ERROR: IORT tabe Revision E.c is deprecated and must not be used.\n" | |
| ); | |
| } | |
| 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; | |
| case EFI_ACPI_IORT_TYPE_RMR: | |
| DumpIortNodeRmr ( | |
| NodePtr, | |
| *IortNodeLength, | |
| *IortIdMappingCount, | |
| *IortIdMappingOffset | |
| ); | |
| break; | |
| default: | |
| IncrementErrorCount (); | |
| Print (L"ERROR: Unsupported IORT Node type = %d\n", *IortNodeType); | |
| } // switch | |
| NodePtr += (*IortNodeLength); | |
| Offset += (*IortNodeLength); | |
| } // while | |
| } |