audk/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Iort/IortParser.c

718 lines
19 KiB
C

/** @file
IORT table parser
Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- IO Remapping Table, Platform Design Document, Revision C, 15 May 2017
**/
#include <IndustryStandard/IoRemappingTable.h>
#include <Library/PrintLib.h>
#include <Library/UefiLib.h>
#include "AcpiParser.h"
#include "AcpiTableParser.h"
// Local variables
STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;
/**
The EIORT_NODE enum describes the IORT Node types.
**/
typedef enum IortNode {
Iort_Node_ITS_Group, ///< ITS Group node
Iort_Node_Named_Component, ///< Named Component node
Iort_Node_Root_Complex, ///< Root Complex node
Iort_Node_SMMUV1_V2, ///< SMMU v1/v2 node
Iort_Node_SMMUV3, ///< SMMU v3 node
Iort_Node_PMCG, ///< PMC group node
Iort_Node_Max
} EIORT_NODE;
// Local Variables
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
);
/**
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
);
/**
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}
};
/**
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}
};
/**
An ACPI_PARSER array describing the IORT PMCG node.
**/
STATIC CONST ACPI_PARSER IortNodePmcgParser[] = {
PARSE_IORT_NODE_HEADER (NULL, NULL),
{L"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},
};
/**
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 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.");
}
}
/**
This function parses the IORT Node Id Mapping array.
@param [in] Ptr Pointer to the start of the IORT Table.
@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
DumpIortNodeIdMappings (
IN UINT8* Ptr,
IN UINT32 MappingCount,
IN UINT32 MappingOffset
)
{
UINT8* IdMappingPtr;
UINT32 Index;
UINT32 Offset;
CHAR8 Buffer[40]; // Used for AsciiName param of ParseAcpi
IdMappingPtr = Ptr + MappingOffset;
Index = 0;
while (Index < MappingCount) {
AsciiSPrint (
Buffer,
sizeof (Buffer),
"ID Mapping [%d]",
Index
);
Offset = ParseAcpi (
TRUE,
4,
Buffer,
IdMappingPtr,
20,
PARSER_PARAMS (IortNodeIdMappingParser)
);
IdMappingPtr += Offset;
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
UINT8* ArrayPtr;
ParseAcpi (
TRUE,
2,
"SMMUv1 or SMMUv2 Node",
Ptr,
Length,
PARSER_PARAMS (IortNodeSmmuV1V2Parser)
);
ArrayPtr = Ptr + *InterruptContextOffset;
Index = 0;
while (Index < *InterruptContextCount) {
AsciiSPrint (
Buffer,
sizeof (Buffer),
"Context Interrupts Array [%d]",
Index
);
Offset = ParseAcpi (
TRUE,
4,
Buffer,
ArrayPtr,
8,
PARSER_PARAMS (InterruptArrayParser)
);
ArrayPtr += Offset;
Index++;
}
ArrayPtr = Ptr + *PmuInterruptOffset;
Index = 0;
while (Index < *PmuInterruptCount) {
AsciiSPrint (
Buffer,
sizeof (Buffer),
"PMU Interrupts Array [%d]",
Index
);
Offset = ParseAcpi (
TRUE,
4,
Buffer,
ArrayPtr,
8,
PARSER_PARAMS (InterruptArrayParser)
);
ArrayPtr += Offset;
Index++;
}
if (*IortIdMappingCount != 0) {
DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);
}
}
/**
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)
);
if (*IortIdMappingCount != 0) {
DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);
}
}
/**
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;
UINT8* ItsIdPtr;
CHAR8 Buffer[80]; // Used for AsciiName param of ParseAcpi
Offset = ParseAcpi (
TRUE,
2,
"ITS Node",
Ptr,
Length,
PARSER_PARAMS (IortNodeItsParser)
);
ItsIdPtr = Ptr + Offset;
Index = 0;
while (Index < *ItsCount) {
AsciiSPrint (
Buffer,
sizeof (Buffer),
"GIC ITS Identifier Array [%d]",
Index
);
Offset = ParseAcpi (
TRUE,
4,
Buffer,
ItsIdPtr,
4,
PARSER_PARAMS (ItsIdParser)
);
ItsIdPtr += Offset;
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;
UINT32 Index;
UINT8* DeviceNamePtr;
UINT32 DeviceNameLength;
Offset = ParseAcpi (
TRUE,
2,
"Named Component Node",
Ptr,
Length,
PARSER_PARAMS (IortNodeNamedComponentParser)
);
DeviceNamePtr = Ptr + Offset;
// Estimate the Device Name length
DeviceNameLength = Length - Offset - (MappingCount * 20);
PrintFieldName (2, L"Device Object Name");
Index = 0;
while ((Index < DeviceNameLength) && (DeviceNamePtr[Index] != 0)) {
Print (L"%c", DeviceNamePtr[Index++]);
}
Print (L"\n");
if (*IortIdMappingCount != 0) {
DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);
}
}
/**
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)
);
if (*IortIdMappingCount != 0) {
DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);
}
}
/**
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)
);
if (*IortIdMappingCount != 0) {
DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);
}
if (*IortIdMappingCount > 1) {
IncrementErrorCount ();
Print (
L"ERROR: ID mapping must not be greater than 1. Id Mapping Count =%d\n",
*IortIdMappingCount
);
}
}
/**
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)
);
Offset = *IortNodeOffset;
NodePtr = Ptr + Offset;
Index = 0;
while ((Index < *IortNodeCount) && (Offset < AcpiTableLength)) {
// Parse the IORT Node Header
ParseAcpi (
FALSE,
0,
"IORT Node Header",
NodePtr,
16,
PARSER_PARAMS (IortNodeHeaderParser)
);
if (*IortNodeLength == 0) {
IncrementErrorCount ();
Print (L"ERROR: Parser error. Invalid table data.\n");
return;
}
PrintFieldName (2, L"* Node Offset *");
Print (L"0x%x\n", Offset);
switch (*IortNodeType) {
case Iort_Node_ITS_Group:
DumpIortNodeIts (
NodePtr,
*IortNodeLength
);
break;
case Iort_Node_Named_Component:
DumpIortNodeNamedComponent (
NodePtr,
*IortNodeLength,
*IortIdMappingCount,
*IortIdMappingOffset
);
break;
case Iort_Node_Root_Complex:
DumpIortNodeRootComplex (
NodePtr,
*IortNodeLength,
*IortIdMappingCount,
*IortIdMappingOffset
);
break;
case Iort_Node_SMMUV1_V2:
DumpIortNodeSmmuV1V2 (
NodePtr,
*IortNodeLength,
*IortIdMappingCount,
*IortIdMappingOffset
);
break;
case Iort_Node_SMMUV3:
DumpIortNodeSmmuV3 (
NodePtr,
*IortNodeLength,
*IortIdMappingCount,
*IortIdMappingOffset
);
break;
case Iort_Node_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
}