/** @file\r
IORT table parser\r
\r
- Copyright (c) 2016 - 2019, ARM Limited. All rights reserved.\r
+ Copyright (c) 2016 - 2020, ARM Limited. All rights reserved.\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
@par Reference(s):\r
- - IO Remapping Table, Platform Design Document, Revision C, 15 May 2017\r
+ - IO Remapping Table, Platform Design Document, Revision D, March 2018\r
**/\r
\r
#include <IndustryStandard/IoRemappingTable.h>\r
#include <Library/UefiLib.h>\r
#include "AcpiParser.h"\r
#include "AcpiTableParser.h"\r
+#include "AcpiViewConfig.h"\r
\r
// Local variables\r
STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;\r
ValidateItsIdMappingCount (\r
IN UINT8* Ptr,\r
IN VOID* Context\r
- );\r
+ )\r
+{\r
+ if (*(UINT32*)Ptr != 0) {\r
+ IncrementErrorCount ();\r
+ Print (L"\nERROR: IORT ID Mapping count must be zero.");\r
+ }\r
+}\r
+\r
+/**\r
+ This function validates the ID Mapping array count for the Performance\r
+ Monitoring Counter Group (PMCG) node.\r
+\r
+ @param [in] Ptr Pointer to the start of the field data.\r
+ @param [in] Context Pointer to context specific information e.g. this\r
+ could be a pointer to the ACPI table header.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+ValidatePmcgIdMappingCount (\r
+ IN UINT8* Ptr,\r
+ IN VOID* Context\r
+ )\r
+{\r
+ if (*(UINT32*)Ptr > 1) {\r
+ IncrementErrorCount ();\r
+ Print (L"\nERROR: IORT ID Mapping count must not be greater than 1.");\r
+ }\r
+}\r
\r
/**\r
This function validates the ID Mapping array offset for the ITS node.\r
ValidateItsIdArrayReference (\r
IN UINT8* Ptr,\r
IN VOID* Context\r
- );\r
+ )\r
+{\r
+ if (*(UINT32*)Ptr != 0) {\r
+ IncrementErrorCount ();\r
+ Print (L"\nERROR: IORT ID Mapping offset must be zero.");\r
+ }\r
+}\r
\r
/**\r
Helper Macro for populating the IORT Node header in the ACPI_PARSER array.\r
An ACPI_PARSER array describing the SMMUv1/2 Node Interrupt Array.\r
**/\r
STATIC CONST ACPI_PARSER InterruptArrayParser[] = {\r
- {L" Interrupt GSIV", 4, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
- {L" Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}\r
+ {L"Interrupt GSIV", 4, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}\r
};\r
\r
/**\r
An ACPI_PARSER array describing the IORT ID Mapping.\r
**/\r
STATIC CONST ACPI_PARSER IortNodeIdMappingParser[] = {\r
- {L" Input base", 4, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
- {L" Number of IDs", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
- {L" Output base", 4, 8, L"0x%x", NULL, NULL, NULL, NULL},\r
- {L" Output reference", 4, 12, L"0x%x", NULL, NULL, NULL, NULL},\r
- {L" Flags", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}\r
+ {L"Input base", 4, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Number of IDs", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Output base", 4, 8, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Output reference", 4, 12, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Flags", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}\r
};\r
\r
/**\r
{L"Event", 4, 44, L"0x%x", NULL, NULL, NULL, NULL},\r
{L"PRI", 4, 48, L"0x%x", NULL, NULL, NULL, NULL},\r
{L"GERR", 4, 52, L"0x%x", NULL, NULL, NULL, NULL},\r
- {L"Sync", 4, 56, L"0x%x", NULL, NULL, NULL, NULL}\r
+ {L"Sync", 4, 56, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Proximity domain", 4, 60, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Device ID mapping index", 4, 64, L"%d", NULL, NULL, NULL, NULL}\r
};\r
\r
/**\r
ValidateItsIdMappingCount,\r
ValidateItsIdArrayReference\r
),\r
- {L" Number of ITSs", 4, 16, L"%d", NULL, (VOID**)&ItsCount, NULL}\r
+ {L"Number of ITSs", 4, 16, L"%d", NULL, (VOID**)&ItsCount, NULL}\r
};\r
\r
/**\r
An ACPI_PARSER array describing the ITS ID.\r
**/\r
STATIC CONST ACPI_PARSER ItsIdParser[] = {\r
- { L" GIC ITS Identifier", 4, 0, L"%d", NULL, NULL, NULL }\r
+ { L"GIC ITS Identifier", 4, 0, L"%d", NULL, NULL, NULL }\r
};\r
\r
/**\r
PARSE_IORT_NODE_HEADER (NULL, NULL),\r
{L"Memory access properties", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL},\r
{L"ATS Attribute", 4, 24, L"0x%x", NULL, NULL, NULL, NULL},\r
- {L"PCI Segment number", 4, 28, L"0x%x", NULL, NULL, NULL, NULL}\r
+ {L"PCI Segment number", 4, 28, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Memory access size limit", 1, 32, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Reserved", 3, 33, L"%x %x %x", Dump3Chars, NULL, NULL, NULL}\r
};\r
\r
/**\r
An ACPI_PARSER array describing the IORT PMCG node.\r
**/\r
STATIC CONST ACPI_PARSER IortNodePmcgParser[] = {\r
- PARSE_IORT_NODE_HEADER (NULL, NULL),\r
- {L"Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL},\r
+ PARSE_IORT_NODE_HEADER (ValidatePmcgIdMappingCount, NULL),\r
+ {L"Page 0 Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL},\r
{L"Overflow interrupt GSIV", 4, 24, L"0x%x", NULL, NULL, NULL, NULL},\r
{L"Node reference", 4, 28, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Page 1 Base Address", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL}\r
};\r
\r
-/**\r
- This function validates the ID Mapping array count for the ITS node.\r
-\r
- @param [in] Ptr Pointer to the start of the field data.\r
- @param [in] Context Pointer to context specific information e.g. this\r
- could be a pointer to the ACPI table header.\r
-**/\r
-STATIC\r
-VOID\r
-EFIAPI\r
-ValidateItsIdMappingCount (\r
- IN UINT8* Ptr,\r
- IN VOID* Context\r
- )\r
-{\r
- if (*(UINT32*)Ptr != 0) {\r
- IncrementErrorCount ();\r
- Print (L"\nERROR: IORT ID Mapping count must be zero.");\r
- }\r
-}\r
-\r
-/**\r
- This function validates the ID Mapping array offset for the ITS node.\r
-\r
- @param [in] Ptr Pointer to the start of the field data.\r
- @param [in] Context Pointer to context specific information e.g. this\r
- could be a pointer to the ACPI table header.\r
-**/\r
-STATIC\r
-VOID\r
-EFIAPI\r
-ValidateItsIdArrayReference (\r
- IN UINT8* Ptr,\r
- IN VOID* Context\r
- )\r
-{\r
- if (*(UINT32*)Ptr != 0) {\r
- IncrementErrorCount ();\r
- Print (L"\nERROR: IORT ID Mapping offset must be zero.");\r
- }\r
-}\r
-\r
/**\r
This function parses the IORT Node Id Mapping array.\r
\r
- @param [in] Ptr Pointer to the start of the IORT Table.\r
+ @param [in] Ptr Pointer to the start of the ID mapping array.\r
+ @param [in] Length Length of the buffer.\r
@param [in] MappingCount The ID Mapping count.\r
- @param [in] MappingOffset The offset of the ID Mapping array\r
- from the start of the IORT table.\r
**/\r
STATIC\r
VOID\r
DumpIortNodeIdMappings (\r
IN UINT8* Ptr,\r
- IN UINT32 MappingCount,\r
- IN UINT32 MappingOffset\r
+ IN UINT32 Length,\r
+ IN UINT32 MappingCount\r
)\r
{\r
- UINT8* IdMappingPtr;\r
UINT32 Index;\r
UINT32 Offset;\r
CHAR8 Buffer[40]; // Used for AsciiName param of ParseAcpi\r
\r
- IdMappingPtr = Ptr + MappingOffset;\r
Index = 0;\r
- while (Index < MappingCount) {\r
+ Offset = 0;\r
+\r
+ while ((Index < MappingCount) &&\r
+ (Offset < Length)) {\r
AsciiSPrint (\r
Buffer,\r
sizeof (Buffer),\r
"ID Mapping [%d]",\r
Index\r
);\r
- Offset = ParseAcpi (\r
- TRUE,\r
- 4,\r
- Buffer,\r
- IdMappingPtr,\r
- 20,\r
- PARSER_PARAMS (IortNodeIdMappingParser)\r
- );\r
- IdMappingPtr += Offset;\r
+ Offset += ParseAcpi (\r
+ TRUE,\r
+ 4,\r
+ Buffer,\r
+ Ptr + Offset,\r
+ Length - Offset,\r
+ PARSER_PARAMS (IortNodeIdMappingParser)\r
+ );\r
Index++;\r
}\r
}\r
UINT32 Offset;\r
CHAR8 Buffer[50]; // Used for AsciiName param of ParseAcpi\r
\r
- UINT8* ArrayPtr;\r
-\r
ParseAcpi (\r
TRUE,\r
2,\r
PARSER_PARAMS (IortNodeSmmuV1V2Parser)\r
);\r
\r
- ArrayPtr = Ptr + *InterruptContextOffset;\r
+ // Check if the values used to control the parsing logic have been\r
+ // successfully read.\r
+ if ((InterruptContextCount == NULL) ||\r
+ (InterruptContextOffset == NULL) ||\r
+ (PmuInterruptCount == NULL) ||\r
+ (PmuInterruptOffset == NULL)) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Insufficient SMMUv1/2 node length. Length = %d\n",\r
+ Length\r
+ );\r
+ return;\r
+ }\r
+\r
+ Offset = *InterruptContextOffset;\r
Index = 0;\r
- while (Index < *InterruptContextCount) {\r
+\r
+ while ((Index < *InterruptContextCount) &&\r
+ (Offset < Length)) {\r
AsciiSPrint (\r
Buffer,\r
sizeof (Buffer),\r
"Context Interrupts Array [%d]",\r
Index\r
);\r
- Offset = ParseAcpi (\r
- TRUE,\r
- 4,\r
- Buffer,\r
- ArrayPtr,\r
- 8,\r
- PARSER_PARAMS (InterruptArrayParser)\r
- );\r
- ArrayPtr += Offset;\r
+ Offset += ParseAcpi (\r
+ TRUE,\r
+ 4,\r
+ Buffer,\r
+ Ptr + Offset,\r
+ Length - Offset,\r
+ PARSER_PARAMS (InterruptArrayParser)\r
+ );\r
Index++;\r
}\r
\r
- ArrayPtr = Ptr + *PmuInterruptOffset;\r
+ Offset = *PmuInterruptOffset;\r
Index = 0;\r
- while (Index < *PmuInterruptCount) {\r
+\r
+ while ((Index < *PmuInterruptCount) &&\r
+ (Offset < Length)) {\r
AsciiSPrint (\r
Buffer,\r
sizeof (Buffer),\r
"PMU Interrupts Array [%d]",\r
Index\r
);\r
- Offset = ParseAcpi (\r
- TRUE,\r
- 4,\r
- Buffer,\r
- ArrayPtr,\r
- 8,\r
- PARSER_PARAMS (InterruptArrayParser)\r
- );\r
- ArrayPtr += Offset;\r
+ Offset += ParseAcpi (\r
+ TRUE,\r
+ 4,\r
+ Buffer,\r
+ Ptr + Offset,\r
+ Length - Offset,\r
+ PARSER_PARAMS (InterruptArrayParser)\r
+ );\r
Index++;\r
}\r
\r
- if (*IortIdMappingCount != 0) {\r
- DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);\r
- }\r
+ DumpIortNodeIdMappings (\r
+ Ptr + MappingOffset,\r
+ Length - MappingOffset,\r
+ MappingCount\r
+ );\r
}\r
\r
/**\r
PARSER_PARAMS (IortNodeSmmuV3Parser)\r
);\r
\r
- if (*IortIdMappingCount != 0) {\r
- DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);\r
- }\r
+ DumpIortNodeIdMappings (\r
+ Ptr + MappingOffset,\r
+ Length - MappingOffset,\r
+ MappingCount\r
+ );\r
}\r
\r
/**\r
{\r
UINT32 Offset;\r
UINT32 Index;\r
- UINT8* ItsIdPtr;\r
CHAR8 Buffer[80]; // Used for AsciiName param of ParseAcpi\r
\r
Offset = ParseAcpi (\r
- TRUE,\r
- 2,\r
- "ITS Node",\r
- Ptr,\r
- Length,\r
- PARSER_PARAMS (IortNodeItsParser)\r
- );\r
+ TRUE,\r
+ 2,\r
+ "ITS Node",\r
+ Ptr,\r
+ Length,\r
+ PARSER_PARAMS (IortNodeItsParser)\r
+ );\r
+\r
+ // Check if the values used to control the parsing logic have been\r
+ // successfully read.\r
+ if (ItsCount == NULL) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Insufficient ITS group length. Length = %d.\n",\r
+ Length\r
+ );\r
+ return;\r
+ }\r
\r
- ItsIdPtr = Ptr + Offset;\r
Index = 0;\r
- while (Index < *ItsCount) {\r
+\r
+ while ((Index < *ItsCount) &&\r
+ (Offset < Length)) {\r
AsciiSPrint (\r
Buffer,\r
sizeof (Buffer),\r
"GIC ITS Identifier Array [%d]",\r
Index\r
);\r
- Offset = ParseAcpi (\r
- TRUE,\r
- 4,\r
- Buffer,\r
- ItsIdPtr,\r
- 4,\r
- PARSER_PARAMS (ItsIdParser)\r
- );\r
- ItsIdPtr += Offset;\r
+ Offset += ParseAcpi (\r
+ TRUE,\r
+ 4,\r
+ Buffer,\r
+ Ptr + Offset,\r
+ Length - Offset,\r
+ PARSER_PARAMS (ItsIdParser)\r
+ );\r
Index++;\r
}\r
\r
// Note: ITS does not have the ID Mappings Array\r
+\r
}\r
\r
/**\r
)\r
{\r
UINT32 Offset;\r
- UINT32 Index;\r
- UINT8* DeviceNamePtr;\r
- UINT32 DeviceNameLength;\r
\r
Offset = ParseAcpi (\r
TRUE,\r
PARSER_PARAMS (IortNodeNamedComponentParser)\r
);\r
\r
- DeviceNamePtr = Ptr + Offset;\r
// Estimate the Device Name length\r
- DeviceNameLength = Length - Offset - (MappingCount * 20);\r
PrintFieldName (2, L"Device Object Name");\r
- Index = 0;\r
- while ((Index < DeviceNameLength) && (DeviceNamePtr[Index] != 0)) {\r
- Print (L"%c", DeviceNamePtr[Index++]);\r
+\r
+ while ((*(Ptr + Offset) != 0) &&\r
+ (Offset < Length)) {\r
+ Print (L"%c", *(Ptr + Offset));\r
+ Offset++;\r
}\r
Print (L"\n");\r
\r
- if (*IortIdMappingCount != 0) {\r
- DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);\r
- }\r
+ DumpIortNodeIdMappings (\r
+ Ptr + MappingOffset,\r
+ Length - MappingOffset,\r
+ MappingCount\r
+ );\r
}\r
\r
/**\r
PARSER_PARAMS (IortNodeRootComplexParser)\r
);\r
\r
- if (*IortIdMappingCount != 0) {\r
- DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);\r
- }\r
+ DumpIortNodeIdMappings (\r
+ Ptr + MappingOffset,\r
+ Length - MappingOffset,\r
+ MappingCount\r
+ );\r
}\r
\r
/**\r
Ptr,\r
Length,\r
PARSER_PARAMS (IortNodePmcgParser)\r
- );\r
-\r
- if (*IortIdMappingCount != 0) {\r
- DumpIortNodeIdMappings (Ptr, MappingCount, MappingOffset);\r
- }\r
+ );\r
\r
- if (*IortIdMappingCount > 1) {\r
- IncrementErrorCount ();\r
- Print (\r
- L"ERROR: ID mapping must not be greater than 1. Id Mapping Count =%d\n",\r
- *IortIdMappingCount\r
- );\r
- }\r
+ DumpIortNodeIdMappings (\r
+ Ptr + MappingOffset,\r
+ Length - MappingOffset,\r
+ MappingCount\r
+ );\r
}\r
\r
/**\r
AcpiTableLength,\r
PARSER_PARAMS (IortParser)\r
);\r
+\r
+ // Check if the values used to control the parsing logic have been\r
+ // successfully read.\r
+ if ((IortNodeCount == NULL) ||\r
+ (IortNodeOffset == NULL)) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Insufficient table length. AcpiTableLength = %d.\n",\r
+ AcpiTableLength\r
+ );\r
+ return;\r
+ }\r
+\r
Offset = *IortNodeOffset;\r
NodePtr = Ptr + Offset;\r
Index = 0;\r
\r
- while ((Index < *IortNodeCount) && (Offset < AcpiTableLength)) {\r
+ // Parse the specified number of IORT nodes or the IORT table buffer length.\r
+ // Whichever is minimum.\r
+ while ((Index++ < *IortNodeCount) &&\r
+ (Offset < AcpiTableLength)) {\r
// Parse the IORT Node Header\r
ParseAcpi (\r
FALSE,\r
0,\r
"IORT Node Header",\r
NodePtr,\r
- 16,\r
+ AcpiTableLength - Offset,\r
PARSER_PARAMS (IortNodeHeaderParser)\r
);\r
- if (*IortNodeLength == 0) {\r
+\r
+ // Check if the values used to control the parsing logic have been\r
+ // successfully read.\r
+ if ((IortNodeType == NULL) ||\r
+ (IortNodeLength == NULL) ||\r
+ (IortIdMappingCount == NULL) ||\r
+ (IortIdMappingOffset == NULL)) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Insufficient remaining table buffer length to read the " \\r
+ L"IORT node header. Length = %d.\n",\r
+ AcpiTableLength - Offset\r
+ );\r
+ return;\r
+ }\r
+\r
+ // Validate IORT Node length\r
+ if ((*IortNodeLength == 0) ||\r
+ ((Offset + (*IortNodeLength)) > AcpiTableLength)) {\r
IncrementErrorCount ();\r
- Print (L"ERROR: Parser error. Invalid table data.\n");\r
+ Print (\r
+ L"ERROR: Invalid IORT Node length. " \\r
+ L"Length = %d. Offset = %d. AcpiTableLength = %d.\n",\r
+ *IortNodeLength,\r
+ Offset,\r
+ AcpiTableLength\r
+ );\r
return;\r
}\r
\r