/** @file RISC-V IO Mapping Table (RIMT) parser Copyright (c) 2025, Plasteli.net. All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent Reference(s): - ACPI 6.6 Specification - RISC-V IO Mapping Table (RIMT) Specification Version v1.0, 2025-03-31: Ratified **/ #include #include #include #include "AcpiParser.h" #include "AcpiTableParser.h" #define SIZE_OF_T(TYPE, Field) ((UINTN)sizeof(((TYPE *)0)->Field)) // Local variables STATIC UINT8 *mRimtNodeType; STATIC UINT16 *mRimtNodeLength; STATIC EFI_ACPI_6_6_RIMT_STRUCTURE mRimtInfo; STATIC CONST UINT32 *mNumberOfRimtNodes; STATIC CONST UINT32 *mOffsetToRimtNodeArray; STATIC CONST UINT16 *mNumberOfIdMappings; STATIC UINT8 *mIdMappingArrayOffset; /** This function validates RIMT Node type. @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 RimtValidateNodeType ( IN UINT8 *Ptr, IN UINT32 Length, IN VOID *Context ) { UINT8 NodeType = *(UINT8 *)Ptr; if (NodeType >= RimtNodeUnsupported) { IncrementErrorCount (); Print (L"\nERROR: Unrecognized RIMT node type. Type value must be less than %d but got %d", RimtNodeUnsupported, NodeType); } } /** This function traces RIMT IOMMU Node Type field and presents in human-readable form. @param [in] Format Optional format string for tracing the data. @param [in] Ptr Pointer to the start of the buffer. @param [in] Length Length of the field. **/ STATIC VOID EFIAPI RimtNodeTypeToStr ( CONST CHAR16 *Format, UINT8 *Ptr, UINT32 Length ) { CHAR8 *Str; UINT8 NodeType; NodeType = *(UINT8 *)Ptr; if (NodeType == RimtNodeIommu) { Str = "IOMMU"; } else if (NodeType == RimtNodePcieRc) { Str = "PCIe Root Complex"; } else if (NodeType == RimtNodePlatform) { Str = "Platform Device"; } else { Str = "Unknown"; } AsciiPrint (Str); } /** Helper Macro for populating the RIMT Node header in the ACPI_PARSER array. Every RIMT Node (IOMMU, PCIe Root Complex, PLatform Device) has this header common **/ #define RIMT_PARSE_NODE_HEADER \ { L"Type", \ SIZE_OF_T(EFI_ACPI_6_6_RIMT_NODE_HEADER_STRUCTURE, Type), \ OFFSET_OF(EFI_ACPI_6_6_RIMT_NODE_HEADER_STRUCTURE, Type), \ NULL, \ RimtNodeTypeToStr, \ (VOID**)&mRimtNodeType, \ RimtValidateNodeType, \ NULL \ }, \ { L"Revision", \ SIZE_OF_T(EFI_ACPI_6_6_RIMT_NODE_HEADER_STRUCTURE, Revision),\ OFFSET_OF(EFI_ACPI_6_6_RIMT_NODE_HEADER_STRUCTURE, Revision),\ L"%d", \ NULL, \ NULL, \ NULL, \ NULL \ }, \ { L"Length", \ SIZE_OF_T(EFI_ACPI_6_6_RIMT_NODE_HEADER_STRUCTURE, Length), \ OFFSET_OF(EFI_ACPI_6_6_RIMT_NODE_HEADER_STRUCTURE, Length), \ L"%d", \ NULL, \ (VOID**)&mRimtNodeLength, \ NULL, \ NULL \ }, \ { L"Reserved", \ SIZE_OF_T(EFI_ACPI_6_6_RIMT_NODE_HEADER_STRUCTURE, Reserved),\ OFFSET_OF(EFI_ACPI_6_6_RIMT_NODE_HEADER_STRUCTURE, Reserved),\ L"0x%x", \ NULL, \ NULL, \ NULL, \ NULL \ }, \ { L"Id", \ SIZE_OF_T(EFI_ACPI_6_6_RIMT_NODE_HEADER_STRUCTURE, Id), \ OFFSET_OF(EFI_ACPI_6_6_RIMT_NODE_HEADER_STRUCTURE, Id), \ L"%d", \ NULL, \ NULL, \ NULL, \ NULL \ } \ /** An ACPI_PARSER array describing Parser for the RIMT node header structure. **/ STATIC CONST ACPI_PARSER mRimtNodeHeaderParser[] = { RIMT_PARSE_NODE_HEADER }; /** This function validates number of RIMT nodes. According to RIMT spec, Chapter 2.1, system with a single IOMMU, should have at least two RIMT nodes @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 RimtValidateNumberOfNodes ( UINT8 *Ptr, UINT32 Length, VOID *Context ) { UINT32 NumNodes; NumNodes = *(UINT32 *)Ptr; if (NumNodes < RIMT_MINIMAL_NUMBER_OF_NODES_ALLOWED) { IncrementErrorCount (); Print (L"\nERROR: Minimal Number of RIMT nodes must be at least %d.", RIMT_MINIMAL_NUMBER_OF_NODES_ALLOWED); } } /** An ACPI_PARSER array describing the RIMT (RISC-V IO Mapping Table). **/ STATIC CONST ACPI_PARSER mRimtParser[] = { PARSE_ACPI_HEADER (&mRimtInfo.Header), { L"Number of RIMT Nodes", SIZE_OF_T (EFI_ACPI_6_6_RIMT_STRUCTURE,NumberOfRimtNodes), OFFSET_OF (EFI_ACPI_6_6_RIMT_STRUCTURE,NumberOfRimtNodes), L"%d", NULL, (VOID **)&mNumberOfRimtNodes, RimtValidateNumberOfNodes, NULL }, { L"Offset to RIMT Node Array", SIZE_OF_T (EFI_ACPI_6_6_RIMT_STRUCTURE,OffsetToRimtNodeArray), OFFSET_OF (EFI_ACPI_6_6_RIMT_STRUCTURE,OffsetToRimtNodeArray), L"0x%x", NULL, (VOID **)&mOffsetToRimtNodeArray, NULL, NULL }, { L"Reserved", SIZE_OF_T (EFI_ACPI_6_6_RIMT_STRUCTURE,Reserved), OFFSET_OF (EFI_ACPI_6_6_RIMT_STRUCTURE,Reserved), L"0x%x", NULL, NULL, NULL, NULL } }; /** This macro generates function definition for parser tracing Flags field of RIMT Node. @param [in] Parser An ACPI_PARSER for tracing the data. **/ #define RIMT_DECLARE_NODE_FLAGS_PARSER_FUNC(Parser) \ STATIC \ VOID \ EFIAPI \ _RimtNodeFlagsParser ## Parser ( \ CONST CHAR16 *Format, \ UINT8 *Ptr, \ UINT32 Length \ ) \ { \ UINT32* Flags; \ \ Flags = (UINT32 *)Ptr; \ Print (L"0x%X\n", *Flags); \ ParseAcpiBitFields ( \ TRUE, \ 2, \ NULL, \ (UINT8 *)Flags, \ sizeof(Flags), \ PARSER_PARAMS (Parser) \ ); \ } \ #define RIMT_GET_NODE_FLAGS_PARSER_FUNC(Parser) _RimtNodeFlagsParser ## Parser /** This macro generates function definition which traces bits in Flags field. @param [in] Parser Optional format string for tracing the data. @param [in] Active String to display if interpreted bit is active. @param [in] Inactive String to display if interpreted bit is inactive. **/ #define RIMT_DECLARE_FLAGS_BIT_PARSER_FUNC(Parser, Active, Inactive) \ STATIC \ VOID \ EFIAPI \ _RimtFlagsToStr ## Parser ( \ CONST CHAR16 *Format OPTIONAL, \ UINT8 *Ptr, \ UINT32 Length \ ) \ { \ CHAR8 *Str; \ \ if ((*(UINT32 *)Ptr & 0x1) == 1) \ Str = #Active ; \ else \ Str = #Inactive ; \ AsciiPrint (Str); \ } \ /** This macro gets generated function name which traces bits in Flags field defined by DECLARE_FLAG_INTERPRETER() **/ #define RIMT_GET_FLAGS_BIT_PARSER_FUNC(interpreter) _RimtFlagsToStr ## interpreter /** This function prints Hardwareld field. If no format string is specified the Format must be NULL. @param [in] Format Optional format string for tracing the data. @param [in] Ptr Pointer to the start of the buffer. @param [in] Length Length of the field. **/ STATIC VOID EFIAPI RimtHardwareIdToStr ( CONST CHAR16 *Format, UINT8 *Ptr, UINT32 Length ) { UINT64 *HardwareId; // RIMT specifies HardwareId field as 8-byte long CHAR8 Buffer[9]; HardwareId = (UINT64 *)Ptr; AsciiStrnCpyS (Buffer, sizeof (Buffer), (CHAR8 *)HardwareId, sizeof (*HardwareId)); AsciiPrint (Buffer); Print (L" (0x%lx)", *HardwareId); } RIMT_DECLARE_FLAGS_BIT_PARSER_FUNC (IommuType, "PCIe", "Platform"); RIMT_DECLARE_FLAGS_BIT_PARSER_FUNC (ProximityDomain, "Valid", "Invalid"); STATIC CONST ACPI_PARSER RimtIommuFlagParser[] = { { L"Device Type", RIMT_IOMMU_FLAGS_TYPE_BIT_COUNT, RIMT_IOMMU_FLAGS_TYPE_BIT_OFFSET, NULL, RIMT_GET_FLAGS_BIT_PARSER_FUNC (IommuType), NULL, NULL, NULL }, { L"Proximity Domain", RIMT_IOMMU_FLAGS_PROXIMITY_DOMAIN_BIT_COUNT, RIMT_IOMMU_FLAGS_PROXIMITY_DOMAIN_BIT_OFFSET, NULL, RIMT_GET_FLAGS_BIT_PARSER_FUNC (ProximityDomain), NULL, NULL, NULL }, { L"Reserved", 30, 2, L"0x%x", NULL, NULL, NULL, NULL } }; RIMT_DECLARE_NODE_FLAGS_PARSER_FUNC (RimtIommuFlagParser); /** An ACPI_PARSER array describing the IOMMU Node. **/ STATIC CONST ACPI_PARSER RimtIommuNodeParser[] = { RIMT_PARSE_NODE_HEADER, { L"Hardware ID", SIZE_OF_T (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, HardwareId), OFFSET_OF (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, HardwareId), NULL, RimtHardwareIdToStr, NULL, NULL, NULL }, { L"Base Address", SIZE_OF_T (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, BaseAddress), OFFSET_OF (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, BaseAddress), L"0x%lx", NULL, NULL, NULL, NULL }, { L"Flags", SIZE_OF_T (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, Flags), OFFSET_OF (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, Flags), NULL, RIMT_GET_NODE_FLAGS_PARSER_FUNC (RimtIommuFlagParser), NULL, NULL, NULL }, { L"Proximity Domain", SIZE_OF_T (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, ProximityDomain), OFFSET_OF (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, ProximityDomain), L"%d", NULL, NULL, NULL, NULL }, { L"PCIe Segment number", SIZE_OF_T (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, PcieSegmentNumber), OFFSET_OF (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, PcieSegmentNumber), L"0x%x", NULL, NULL, NULL, NULL }, { L"PCIe B/D/F", SIZE_OF_T (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, PcieBdf), OFFSET_OF (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, PcieBdf), L"%d", NULL, NULL, NULL, NULL }, { L"Number of interrupt wires", SIZE_OF_T (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, NumberOfInterruptWires), OFFSET_OF (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, NumberOfInterruptWires), L"0x%x", NULL, NULL, NULL, NULL }, { L"Interrupt wire array offset", SIZE_OF_T (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, InterruptWireArrayOffset), OFFSET_OF (EFI_ACPI_6_6_RIMT_IOMMU_NODE_STRUCTURE, InterruptWireArrayOffset), L"0x%x", NULL, NULL, NULL, NULL } }; /** This function parses the RIMT IOMMU node. @param [in] Ptr Pointer to the start of the buffer. @param [in] Length Length of the buffer. **/ STATIC VOID EFIAPI RimtParseIommuNode ( IN UINT8 *Ptr, IN UINT16 Length, IN UINT32 Index ) { CHAR8 Buffer[32]; AsciiSPrint ( Buffer, sizeof (Buffer), "RIMT Node [%d]", Index ); ParseAcpi ( TRUE, 2, Buffer, Ptr, Length, PARSER_PARAMS (RimtIommuNodeParser) ); } RIMT_DECLARE_FLAGS_BIT_PARSER_FUNC (IdMappingAtsSupport, "Required", "Not Required"); RIMT_DECLARE_FLAGS_BIT_PARSER_FUNC (IdMappingPriSupport, "Required", "Not Required"); STATIC CONST ACPI_PARSER RimtIdMappingFlagParser[] = { { L"ATS", RIMT_ID_MAPPING_FLAGS_ATS_BIT_COUNT, RIMT_ID_MAPPING_FLAGS_ATS_BIT_OFFSET, NULL, RIMT_GET_FLAGS_BIT_PARSER_FUNC (IdMappingAtsSupport), NULL, NULL, NULL }, { L"PRI", RIMT_ID_MAPPING_FLAGS_PRI_BIT_COUNT, RIMT_ID_MAPPING_FLAGS_PRI_BIT_OFFSET, NULL, RIMT_GET_FLAGS_BIT_PARSER_FUNC (IdMappingPriSupport), NULL, NULL, NULL }, { L"Reserved", 30, 2, L"0x%x", NULL, NULL, NULL, NULL } }; RIMT_DECLARE_NODE_FLAGS_PARSER_FUNC (RimtIdMappingFlagParser); /** An ACPI_PARSER array describing the ID Mapping Node. **/ STATIC CONST ACPI_PARSER RimtIdMappingNodeParser[] = { { L"Source ID Base", SIZE_OF_T (EFI_ACPI_6_6_RIMT_ID_MAPPING_STRUCTURE, SourceIdBase), OFFSET_OF (EFI_ACPI_6_6_RIMT_ID_MAPPING_STRUCTURE, SourceIdBase), L"0x%x", NULL, NULL, NULL, NULL }, { L"Number of IDs", SIZE_OF_T (EFI_ACPI_6_6_RIMT_ID_MAPPING_STRUCTURE, NumberOfIDs), OFFSET_OF (EFI_ACPI_6_6_RIMT_ID_MAPPING_STRUCTURE, NumberOfIDs), L"%d", NULL, NULL, NULL, NULL }, { L"Destination Device ID Base", SIZE_OF_T (EFI_ACPI_6_6_RIMT_ID_MAPPING_STRUCTURE, DestinationDeviceIdBase), OFFSET_OF (EFI_ACPI_6_6_RIMT_ID_MAPPING_STRUCTURE, DestinationDeviceIdBase), L"%d", NULL, NULL, NULL, NULL }, { L"Destination IOMMU Offset", SIZE_OF_T (EFI_ACPI_6_6_RIMT_ID_MAPPING_STRUCTURE, DestinationIommuOffset), OFFSET_OF (EFI_ACPI_6_6_RIMT_ID_MAPPING_STRUCTURE, DestinationIommuOffset), L"0x%x", NULL, NULL, NULL, NULL }, { L"Flags", SIZE_OF_T (EFI_ACPI_6_6_RIMT_ID_MAPPING_STRUCTURE, Flags), OFFSET_OF (EFI_ACPI_6_6_RIMT_ID_MAPPING_STRUCTURE, Flags), NULL, RIMT_GET_NODE_FLAGS_PARSER_FUNC (RimtIdMappingFlagParser), NULL, NULL, NULL }, }; /** This function parses the RIMT ID Mapping node. @param [in] Ptr Pointer to the start of the buffer. @param [in] Length Length of the buffer. @retval Number of bytes parsed. **/ STATIC VOID EFIAPI RimtParseIdMappingArray ( IN UINT8 *Node, IN UINT16 Length, IN UINT32 NumberOfIdMappings ) { UINT32 Index; UINT32 Offset; CHAR8 Buffer[32]; Index = 0; Offset = 0; while ((Index < NumberOfIdMappings) && (Offset < Length)) { AsciiSPrint ( Buffer, sizeof (Buffer), "ID Mapping [%d]", Index ); Offset += ParseAcpi ( TRUE, 4, Buffer, Node + Offset, Length - Offset, PARSER_PARAMS (RimtIdMappingNodeParser) ); ++Index; } } RIMT_DECLARE_FLAGS_BIT_PARSER_FUNC (PcieRcAtsSupport, "Supported", "Not Supported"); RIMT_DECLARE_FLAGS_BIT_PARSER_FUNC (PcieRcPriSupport, "Supported", "Not Supported"); STATIC CONST ACPI_PARSER RimtPcieRcFlagParser[] = { { L"ATS", RIMT_PCIERC_FLAGS_ATS_BIT_COUNT, RIMT_PCIERC_FLAGS_ATS_BIT_OFFSET, NULL, RIMT_GET_FLAGS_BIT_PARSER_FUNC (PcieRcAtsSupport), NULL, NULL, NULL }, { L"PRI", RIMT_PCIERC_FLAGS_PRI_BIT_COUNT, RIMT_PCIERC_FLAGS_PRI_BIT_OFFSET, NULL, RIMT_GET_FLAGS_BIT_PARSER_FUNC (PcieRcPriSupport), NULL, NULL, NULL }, { L"Reserved", 30, 2, L"0x%x", NULL, NULL, NULL, NULL } }; RIMT_DECLARE_NODE_FLAGS_PARSER_FUNC (RimtPcieRcFlagParser); /** An ACPI_PARSER array describing the Pcie Root Complex Node. **/ STATIC CONST ACPI_PARSER RimtPcieRcNodeParser[] = { RIMT_PARSE_NODE_HEADER, { L"Flags", SIZE_OF_T (EFI_ACPI_6_6_RIMT_PCIE_ROOT_COMPLEX_NODE_STRUCTURE,Flags), OFFSET_OF (EFI_ACPI_6_6_RIMT_PCIE_ROOT_COMPLEX_NODE_STRUCTURE,Flags), NULL, RIMT_GET_NODE_FLAGS_PARSER_FUNC (RimtPcieRcFlagParser), NULL, NULL, NULL }, { L"Reserved", SIZE_OF_T (EFI_ACPI_6_6_RIMT_PCIE_ROOT_COMPLEX_NODE_STRUCTURE,Reserved), OFFSET_OF (EFI_ACPI_6_6_RIMT_PCIE_ROOT_COMPLEX_NODE_STRUCTURE,Reserved), L"0x%lx", NULL, NULL, NULL, NULL }, { L"PCIe Segment Number", SIZE_OF_T (EFI_ACPI_6_6_RIMT_PCIE_ROOT_COMPLEX_NODE_STRUCTURE,PcieSegmentNumber), OFFSET_OF (EFI_ACPI_6_6_RIMT_PCIE_ROOT_COMPLEX_NODE_STRUCTURE,PcieSegmentNumber), L"%d", NULL, NULL, NULL, NULL }, { L"Id Mapping Array Offset", SIZE_OF_T (EFI_ACPI_6_6_RIMT_PCIE_ROOT_COMPLEX_NODE_STRUCTURE,IdMappingArrayOffset), OFFSET_OF (EFI_ACPI_6_6_RIMT_PCIE_ROOT_COMPLEX_NODE_STRUCTURE,IdMappingArrayOffset), L"0x%x", NULL, (VOID **)&mIdMappingArrayOffset, NULL, NULL }, { L"Number Of Id Mappings", SIZE_OF_T (EFI_ACPI_6_6_RIMT_PCIE_ROOT_COMPLEX_NODE_STRUCTURE,NumberOfIdMappings), OFFSET_OF (EFI_ACPI_6_6_RIMT_PCIE_ROOT_COMPLEX_NODE_STRUCTURE,NumberOfIdMappings), L"%d", NULL, (VOID **)&mNumberOfIdMappings, NULL, NULL }, }; /** This function parses the RIMT Pcie Root Complex node. This function parses also Id Mappings related to this PCIe Root Complex @param [in] Ptr Pointer to the start of the buffer. @param [in] Length Length of the buffer. **/ STATIC VOID EFIAPI RimtParsePcieRcNode ( IN UINT8 *Ptr, IN UINT16 Length, IN UINT32 Index ) { UINT8 *IdMappingArray; UINT8 *PcieRootComplexNode; CHAR8 Buffer[32]; PcieRootComplexNode = Ptr; AsciiSPrint ( Buffer, sizeof (Buffer), "RIMT Node [%d]", Index ); ParseAcpi ( TRUE, 2, Buffer, PcieRootComplexNode, Length, PARSER_PARAMS (RimtPcieRcNodeParser) ); IdMappingArray = PcieRootComplexNode + *mIdMappingArrayOffset; RimtParseIdMappingArray ( IdMappingArray, Length - *mIdMappingArrayOffset, *mNumberOfIdMappings ); } /** This function parses the RIMT Platform Device node. TODO: Add parsers when PLatform Device node generator in Qemu is ready. @param [in] Ptr Pointer to the start of the buffer. @param [in] Length Length of the buffer. **/ STATIC VOID EFIAPI RimtParsePlatformDeviceNode ( IN UINT8 *Ptr, IN UINT16 Length, IN UINT32 Index ) { Print (L"WARNING: Platform type of RIMT Node not supported yet.\n"); } /** This function parses the ACPI RIMT table. When trace is enabled this function parses the RIMT table and traces the ACPI table fields. @param [in] Trace If TRUE, trace the ACPI fields. @param [in] Rimt Pointer to the start of the RIMT buffer. @param [in] AcpiTableLength Length of the ACPI table. @param [in] AcpiTableRevision Revision of the ACPI table. **/ VOID EFIAPI ParseAcpiRimt ( IN BOOLEAN Trace, IN UINT8 *Rimt, IN UINT32 AcpiTableLength, IN UINT8 AcpiTableRevision ) { UINT8 *NodePtr; UINT32 Offset; UINT32 Index; if (!Trace) { return; } ParseAcpi ( Trace, 0, "RIMT", Rimt, AcpiTableLength, PARSER_PARAMS (mRimtParser) ); // Check if the values used to control the parsing logic have been // successfully read. if ((mNumberOfRimtNodes == NULL) || (mOffsetToRimtNodeArray == NULL)) { IncrementErrorCount (); Print ( L"ERROR: Insufficient table length. AcpiTableLength = %d.\n", AcpiTableLength ); return; } Offset = *mOffsetToRimtNodeArray; NodePtr = Rimt + Offset; Index = 0; while ((Index < *mNumberOfRimtNodes) && (Offset < AcpiTableLength)) { // Parse the RIMT Node Header ParseAcpi ( FALSE, 0, "RIMT Node Header", NodePtr, AcpiTableLength - Offset, PARSER_PARAMS (mRimtNodeHeaderParser) ); // Check if the values used to control the parsing logic have been // successfully read. if ((mRimtNodeType == NULL) || (mRimtNodeLength == NULL)) { IncrementErrorCount (); Print ( L"ERROR: Insufficient remaining table buffer length to read the " \ L"RIMT node header. Length = %d.\n", AcpiTableLength - Offset ); return; } // Validate RIMT Node length if ((*mRimtNodeLength == 0) || ((Offset + (*mRimtNodeLength)) > AcpiTableLength)) { IncrementErrorCount (); Print ( L"ERROR: Invalid RIMT Node length. " \ L"Length = %d. Offset = %d. AcpiTableLength = %d.\n", *mRimtNodeLength, Offset, AcpiTableLength ); return; } switch (*mRimtNodeType) { case RimtNodeIommu: RimtParseIommuNode ( NodePtr, *mRimtNodeLength, Index ); break; case RimtNodePcieRc: RimtParsePcieRcNode ( NodePtr, *mRimtNodeLength, Index ); break; case RimtNodePlatform: RimtParsePlatformDeviceNode ( NodePtr, *mRimtNodeLength, Index ); break; default: IncrementErrorCount (); Print (L"ERROR: Unsupported RIMT Node type = %d\n", *mRimtNodeType); } // switch Index++; NodePtr += (*mRimtNodeLength); Offset += (*mRimtNodeLength); } }