| /** @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 <IndustryStandard/RiscVIoMappingTable.h> | |
| #include <Library/PrintLib.h> | |
| #include <Library/UefiLib.h> | |
| #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); | |
| } | |
| } |