--- /dev/null
+/** @file\r
+ PPTT table parser\r
+\r
+ Copyright (c) 2019, ARM Limited. All rights reserved.\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+ @par Reference(s):\r
+ - ACPI 6.2 Specification - Errata A, September 2017\r
+**/\r
+\r
+#include <Library/PrintLib.h>\r
+#include <Library/UefiLib.h>\r
+#include "AcpiParser.h"\r
+\r
+// Local variables\r
+STATIC CONST UINT8* ProcessorTopologyStructureType;\r
+STATIC CONST UINT8* ProcessorTopologyStructureLength;\r
+STATIC CONST UINT32* NumberOfPrivateResources;\r
+STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;\r
+\r
+/**\r
+ An ACPI_PARSER array describing the ACPI PPTT Table.\r
+**/\r
+STATIC CONST ACPI_PARSER PpttParser[] = {\r
+ PARSE_ACPI_HEADER (&AcpiHdrInfo)\r
+};\r
+\r
+/**\r
+ This function validates the Cache Type Structure (Type 1) Line size field.\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
+ValidateCacheLineSize (\r
+ IN UINT8* Ptr,\r
+ IN VOID* Context\r
+ )\r
+{\r
+#if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)\r
+ // Reference: ARM Architecture Reference Manual ARMv8 (D.a)\r
+ // Section D12.2.25: CCSIDR_EL1, Current Cache Size ID Register\r
+ // LineSize, bits [2:0]\r
+ // (Log2(Number of bytes in cache line)) - 4.\r
+\r
+ UINT16 LineSize;\r
+ LineSize = *(UINT16*)Ptr;\r
+\r
+ if ((LineSize < 16) || (LineSize > 2048)) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"\nERROR: The cache line size must be between 16 and 2048 bytes"\r
+ L" on ARM Platforms."\r
+ );\r
+ return;\r
+ }\r
+\r
+ if ((LineSize & (LineSize - 1)) != 0) {\r
+ IncrementErrorCount ();\r
+ Print (L"\nERROR: The cache line size is not a power of 2.");\r
+ }\r
+#endif\r
+}\r
+\r
+/**\r
+ This function validates the Cache Type Structure (Type 1) Attributes field.\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
+ValidateCacheAttributes (\r
+ IN UINT8* Ptr,\r
+ IN VOID* Context\r
+ )\r
+{\r
+#if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)\r
+ // Reference: Advanced Configuration and Power Interface (ACPI) Specification\r
+ // Version 6.2 Errata A, September 2017\r
+ // Table 5-153: Cache Type Structure\r
+\r
+ UINT8 Attributes;\r
+ Attributes = *(UINT8*)Ptr;\r
+\r
+ if ((Attributes & 0xE0) != 0) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"\nERROR: Attributes bits [7:5] are reserved and must be zero.",\r
+ Attributes\r
+ );\r
+ return;\r
+ }\r
+#endif\r
+}\r
+\r
+/**\r
+ An ACPI_PARSER array describing the processor topology structure header.\r
+**/\r
+STATIC CONST ACPI_PARSER ProcessorTopologyStructureHeaderParser[] = {\r
+ {L"Type", 1, 0, NULL, NULL, (VOID**)&ProcessorTopologyStructureType,\r
+ NULL, NULL},\r
+ {L"Length", 1, 1, NULL, NULL, (VOID**)&ProcessorTopologyStructureLength,\r
+ NULL, NULL},\r
+ {L"Reserved", 2, 2, NULL, NULL, NULL, NULL, NULL}\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the Processor Hierarchy Node Structure - Type 0.\r
+**/\r
+STATIC CONST ACPI_PARSER ProcessorHierarchyNodeStructureParser[] = {\r
+ {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},\r
+ {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},\r
+\r
+ {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Parent", 4, 8, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"ACPI Processor ID", 4, 12, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Number of private resources", 4, 16, L"%d", NULL,\r
+ (VOID**)&NumberOfPrivateResources, NULL, NULL}\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the Cache Type Structure - Type 1.\r
+**/\r
+STATIC CONST ACPI_PARSER CacheTypeStructureParser[] = {\r
+ {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},\r
+ {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},\r
+\r
+ {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Next Level of Cache", 4, 8, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Size", 4, 12, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Number of sets", 4, 16, L"%d", NULL, NULL, NULL, NULL},\r
+ {L"Associativity", 1, 20, L"%d", NULL, NULL, NULL, NULL},\r
+ {L"Attributes", 1, 21, L"0x%x", NULL, NULL, ValidateCacheAttributes, NULL},\r
+ {L"Line size", 2, 22, L"%d", NULL, NULL, ValidateCacheLineSize, NULL}\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the ID Type Structure - Type 2.\r
+**/\r
+STATIC CONST ACPI_PARSER IdStructureParser[] = {\r
+ {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},\r
+ {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},\r
+\r
+ {L"VENDOR_ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"LEVEL_1_ID", 8, 8, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"LEVEL_2_ID", 8, 16, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"MAJOR_REV", 2, 24, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"MINOR_REV", 2, 26, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"SPIN_REV", 2, 28, L"0x%x", NULL, NULL, NULL, NULL},\r
+};\r
+\r
+/**\r
+ This function parses the Processor Hierarchy Node Structure (Type 0).\r
+\r
+ @param [in] Ptr Pointer to the start of the Processor Hierarchy Node\r
+ Structure data.\r
+ @param [in] Length Length of the Processor Hierarchy Node Structure.\r
+**/\r
+STATIC\r
+VOID\r
+DumpProcessorHierarchyNodeStructure (\r
+ IN UINT8* Ptr,\r
+ IN UINT8 Length\r
+ )\r
+{\r
+ UINT8 Offset;\r
+ UINT8* PrivateResourcePtr;\r
+ UINT32 Index;\r
+ CHAR16 Buffer[OUTPUT_FIELD_COLUMN_WIDTH];\r
+\r
+ Offset = ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "Processor Hierarchy Node Structure",\r
+ Ptr,\r
+ Length,\r
+ PARSER_PARAMS (ProcessorHierarchyNodeStructureParser)\r
+ );\r
+\r
+ PrivateResourcePtr = Ptr + Offset;\r
+ Index = 0;\r
+ while (Index < *NumberOfPrivateResources) {\r
+ UnicodeSPrint (\r
+ Buffer,\r
+ sizeof (Buffer),\r
+ L"Private resources [%d]",\r
+ Index\r
+ );\r
+\r
+ PrintFieldName (4, Buffer);\r
+ Print (\r
+ L"0x%x\n",\r
+ *((UINT32*) PrivateResourcePtr)\r
+ );\r
+\r
+ PrivateResourcePtr += sizeof(UINT32);\r
+ Index++;\r
+ }\r
+}\r
+\r
+/**\r
+ This function parses the Cache Type Structure (Type 1).\r
+\r
+ @param [in] Ptr Pointer to the start of the Cache Type Structure data.\r
+ @param [in] Length Length of the Cache Type Structure.\r
+**/\r
+STATIC\r
+VOID\r
+DumpCacheTypeStructure (\r
+ IN UINT8* Ptr,\r
+ IN UINT8 Length\r
+ )\r
+{\r
+ ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "Cache Type Structure",\r
+ Ptr,\r
+ Length,\r
+ PARSER_PARAMS (CacheTypeStructureParser)\r
+ );\r
+}\r
+\r
+/**\r
+ This function parses the ID Structure (Type 2).\r
+\r
+ @param [in] Ptr Pointer to the start of the ID Structure data.\r
+ @param [in] Length Length of the ID Structure.\r
+**/\r
+STATIC\r
+VOID\r
+DumpIDStructure (\r
+ IN UINT8* Ptr,\r
+ IN UINT8 Length\r
+ )\r
+{\r
+ ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "ID Structure",\r
+ Ptr,\r
+ Length,\r
+ PARSER_PARAMS (IdStructureParser)\r
+ );\r
+}\r
+\r
+/**\r
+ This function parses the ACPI PPTT table.\r
+ When trace is enabled this function parses the PPTT table and\r
+ traces the ACPI table fields.\r
+\r
+ This function parses the following processor topology structures:\r
+ - Processor hierarchy node structure (Type 0)\r
+ - Cache Type Structure (Type 1)\r
+ - ID structure (Type 2)\r
+\r
+ This function also performs validation of the ACPI table fields.\r
+\r
+ @param [in] Trace If TRUE, trace the ACPI fields.\r
+ @param [in] Ptr Pointer to the start of the buffer.\r
+ @param [in] AcpiTableLength Length of the ACPI table.\r
+ @param [in] AcpiTableRevision Revision of the ACPI table.\r
+**/\r
+VOID\r
+EFIAPI\r
+ParseAcpiPptt (\r
+ IN BOOLEAN Trace,\r
+ IN UINT8* Ptr,\r
+ IN UINT32 AcpiTableLength,\r
+ IN UINT8 AcpiTableRevision\r
+ )\r
+{\r
+ UINT32 Offset;\r
+ UINT8* ProcessorTopologyStructurePtr;\r
+\r
+ if (!Trace) {\r
+ return;\r
+ }\r
+\r
+ Offset = ParseAcpi (\r
+ TRUE,\r
+ 0,\r
+ "PPTT",\r
+ Ptr,\r
+ AcpiTableLength,\r
+ PARSER_PARAMS (PpttParser)\r
+ );\r
+ ProcessorTopologyStructurePtr = Ptr + Offset;\r
+\r
+ while (Offset < AcpiTableLength) {\r
+ // Parse Processor Hierarchy Node Structure to obtain Type and Length.\r
+ ParseAcpi (\r
+ FALSE,\r
+ 0,\r
+ NULL,\r
+ ProcessorTopologyStructurePtr,\r
+ 4, // Length of the processor topology structure header is 4 bytes\r
+ PARSER_PARAMS (ProcessorTopologyStructureHeaderParser)\r
+ );\r
+\r
+ if ((Offset + (*ProcessorTopologyStructureLength)) > AcpiTableLength) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Invalid processor topology structure length:"\r
+ L" Type = %d, Length = %d\n",\r
+ *ProcessorTopologyStructureType,\r
+ *ProcessorTopologyStructureLength\r
+ );\r
+ break;\r
+ }\r
+\r
+ PrintFieldName (2, L"* Structure Offset *");\r
+ Print (L"0x%x\n", Offset);\r
+\r
+ switch (*ProcessorTopologyStructureType) {\r
+ case EFI_ACPI_6_2_PPTT_TYPE_PROCESSOR:\r
+ DumpProcessorHierarchyNodeStructure (\r
+ ProcessorTopologyStructurePtr,\r
+ *ProcessorTopologyStructureLength\r
+ );\r
+ break;\r
+ case EFI_ACPI_6_2_PPTT_TYPE_CACHE:\r
+ DumpCacheTypeStructure (\r
+ ProcessorTopologyStructurePtr,\r
+ *ProcessorTopologyStructureLength\r
+ );\r
+ break;\r
+ case EFI_ACPI_6_2_PPTT_TYPE_ID:\r
+ DumpIDStructure (\r
+ ProcessorTopologyStructurePtr,\r
+ *ProcessorTopologyStructureLength\r
+ );\r
+ break;\r
+ default:\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Unknown processor topology structure:"\r
+ L" Type = %d, Length = %d\n",\r
+ *ProcessorTopologyStructureType,\r
+ *ProcessorTopologyStructureLength\r
+ );\r
+ }\r
+\r
+ ProcessorTopologyStructurePtr += *ProcessorTopologyStructureLength;\r
+ Offset += *ProcessorTopologyStructureLength;\r
+ } // while\r
+}\r