--- /dev/null
+/**\r
+ GTDT table parser\r
+\r
+ Copyright (c) 2016 - 2018, 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 <IndustryStandard/Acpi.h>\r
+#include <Library/UefiLib.h>\r
+#include "AcpiParser.h"\r
+#include "AcpiTableParser.h"\r
+\r
+// Local variables\r
+STATIC CONST UINT32* GtdtPlatformTimerCount;\r
+STATIC CONST UINT32* GtdtPlatformTimerOffset;\r
+STATIC CONST UINT8* PlatformTimerType;\r
+STATIC CONST UINT16* PlatformTimerLength;\r
+STATIC CONST UINT32* GtBlockTimerCount;\r
+STATIC CONST UINT32* GtBlockTimerOffset;\r
+STATIC CONST UINT16* GtBlockLength;\r
+STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;\r
+\r
+/** This function validates the GT Block timer count.\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
+ValidateGtBlockTimerCount (\r
+ IN UINT8* Ptr,\r
+ IN VOID* Context\r
+ );\r
+\r
+/** An ACPI_PARSER array describing the ACPI GTDT Table.\r
+*/\r
+STATIC CONST ACPI_PARSER GtdtParser[] = {\r
+ PARSE_ACPI_HEADER (&AcpiHdrInfo),\r
+ {L"CntControlBase Physical Address", 8, 36, L"0x%lx", NULL, NULL,\r
+ NULL, NULL},\r
+ {L"Reserved", 4, 44, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Secure EL1 timer GSIV", 4, 48, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Secure EL1 timer FLAGS", 4, 52, L"0x%x", NULL, NULL, NULL, NULL},\r
+\r
+ {L"Non-Secure EL1 timer GSIV", 4, 56, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Non-Secure EL1 timer FLAGS", 4, 60, L"0x%x", NULL, NULL, NULL, NULL},\r
+\r
+ {L"Virtual timer GSIV", 4, 64, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Virtual timer FLAGS", 4, 68, L"0x%x", NULL, NULL, NULL, NULL},\r
+\r
+ {L"Non-Secure EL2 timer GSIV", 4, 72, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Non-Secure EL2 timer FLAGS", 4, 76, L"0x%x", NULL, NULL, NULL, NULL},\r
+\r
+ {L"CntReadBase Physical address", 8, 80, L"0x%lx", NULL, NULL, NULL, NULL},\r
+ {L"Platform Timer Count", 4, 88, L"%d", NULL,\r
+ (VOID**)&GtdtPlatformTimerCount, NULL, NULL},\r
+ {L"Platform Timer Offset", 4, 92, L"0x%x", NULL,\r
+ (VOID**)&GtdtPlatformTimerOffset, NULL, NULL}\r
+};\r
+\r
+/** An ACPI_PARSER array describing the Platform timer header.\r
+*/\r
+STATIC CONST ACPI_PARSER GtPlatformTimerHeaderParser[] = {\r
+ {L"Type", 1, 0, NULL, NULL, (VOID**)&PlatformTimerType, NULL, NULL},\r
+ {L"Length", 2, 1, NULL, NULL, (VOID**)&PlatformTimerLength, NULL, NULL},\r
+ {L"Reserved", 1, 3, NULL, NULL, NULL, NULL, NULL}\r
+};\r
+\r
+/** An ACPI_PARSER array describing the Platform GT Block.\r
+*/\r
+STATIC CONST ACPI_PARSER GtBlockParser[] = {\r
+ {L"Type", 1, 0, L"%d", NULL, NULL, NULL, NULL},\r
+ {L"Length", 2, 1, L"%d", NULL, (VOID**)&GtBlockLength, NULL, NULL},\r
+ {L"Reserved", 1, 3, L"%x", NULL, NULL, NULL, NULL},\r
+ {L"Physical address (CntCtlBase)", 8, 4, L"0x%lx", NULL, NULL, NULL, NULL},\r
+ {L"Timer Count", 4, 12, L"%d", NULL, (VOID**)&GtBlockTimerCount,\r
+ ValidateGtBlockTimerCount, NULL},\r
+ {L"Timer Offset", 4, 16, L"%d", NULL, (VOID**)&GtBlockTimerOffset, NULL,\r
+ NULL}\r
+};\r
+\r
+/** An ACPI_PARSER array describing the GT Block timer.\r
+*/\r
+STATIC CONST ACPI_PARSER GtBlockTimerParser[] = {\r
+ {L"Frame Number", 1, 0, L"%d", NULL, NULL, NULL, NULL},\r
+ {L"Reserved", 3, 1, L"%x %x %x", Dump3Chars, NULL, NULL, NULL},\r
+ {L"Physical address (CntBaseX)", 8, 4, L"0x%lx", NULL, NULL, NULL, NULL},\r
+ {L"Physical address (CntEL0BaseX)", 8, 12, L"0x%lx", NULL, NULL, NULL,\r
+ NULL},\r
+ {L"Physical Timer GSIV", 4, 20, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Physical Timer Flags", 4, 24, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Virtual Timer GSIV", 4, 28, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Virtual Timer Flags", 4, 32, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Common Flags", 4, 36, L"0x%x", NULL, NULL, NULL, NULL}\r
+};\r
+\r
+/** An ACPI_PARSER array describing the Platform Watchdog.\r
+*/\r
+STATIC CONST ACPI_PARSER SBSAGenericWatchdogParser[] = {\r
+ {L"Type", 1, 0, L"%d", NULL, NULL, NULL, NULL},\r
+ {L"Length", 2, 1, L"%d", NULL, NULL, NULL, NULL},\r
+ {L"Reserved", 1, 3, L"%x", NULL, NULL, NULL, NULL},\r
+ {L"RefreshFrame Physical address", 8, 4, L"0x%lx", NULL, NULL, NULL, NULL},\r
+ {L"ControlFrame Physical address", 8, 12, L"0x%lx", NULL, NULL, NULL, NULL},\r
+ {L"Watchdog Timer GSIV", 4, 20, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Watchdog Timer Flags", 4, 24, L"0x%x", NULL, NULL, NULL, NULL}\r
+};\r
+\r
+/** This function validates the GT Block timer count.\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
+ValidateGtBlockTimerCount (\r
+ IN UINT8* Ptr,\r
+ IN VOID* Context\r
+ )\r
+{\r
+ UINT32 BlockTimerCount = *(UINT32*)Ptr;\r
+ if (BlockTimerCount > 8) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"\nERROR: Timer Count = %d. Max Timer Count is 8.",\r
+ BlockTimerCount\r
+ );\r
+ }\r
+}\r
+\r
+/** This function parses the Platform GT Block.\r
+\r
+ @param [in] Ptr Pointer to the start of the GT Block data.\r
+ @param [in] Length Length of the GT Block structure.\r
+*/\r
+STATIC\r
+VOID\r
+DumpGTBlock (\r
+ IN UINT8* Ptr,\r
+ IN UINT16 Length\r
+ )\r
+{\r
+ UINT32 Index;\r
+ UINT32 Offset;\r
+ UINT16 GTBlockTimerLength;\r
+\r
+ Offset = ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "GT Block",\r
+ Ptr,\r
+ Length,\r
+ PARSER_PARAMS (GtBlockParser)\r
+ );\r
+ GTBlockTimerLength = (*GtBlockLength - Offset) / (*GtBlockTimerCount);\r
+ Length -= Offset;\r
+\r
+ if (*GtBlockTimerCount != 0) {\r
+ Ptr += (*GtBlockTimerOffset);\r
+ Index = 0;\r
+ while ((Index < (*GtBlockTimerCount)) && (Length >= GTBlockTimerLength)) {\r
+ Offset = ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "GT Block Timer",\r
+ Ptr,\r
+ GTBlockTimerLength,\r
+ PARSER_PARAMS (GtBlockTimerParser)\r
+ );\r
+ // Increment by GT Block Timer structure size\r
+ Ptr += Offset;\r
+ Length -= Offset;\r
+ Index++;\r
+ }\r
+\r
+ if (Length != 0) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR:GT Block Timer length mismatch. Unparsed %d bytes.\n",\r
+ Length\r
+ );\r
+ }\r
+ }\r
+}\r
+\r
+/** This function parses the Platform Watchdog timer.\r
+\r
+ @param [in] Ptr Pointer to the start of the watchdog timer data.\r
+ @param [in] Length Length of the watchdog timer structure.\r
+*/\r
+STATIC\r
+VOID\r
+DumpWatchdogTimer (\r
+ IN UINT8* Ptr,\r
+ IN UINT16 Length\r
+ )\r
+{\r
+ ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "SBSA Generic Watchdog",\r
+ Ptr,\r
+ Length,\r
+ PARSER_PARAMS (SBSAGenericWatchdogParser)\r
+ );\r
+}\r
+\r
+/** This function parses the ACPI GTDT table.\r
+ When trace is enabled this function parses the GTDT table and\r
+ traces the ACPI table fields.\r
+\r
+ This function also parses the following platform timer structures:\r
+ - GT Block timer\r
+ - Watchdog timer\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
+ParseAcpiGtdt (\r
+ IN BOOLEAN Trace,\r
+ IN UINT8* Ptr,\r
+ IN UINT32 AcpiTableLength,\r
+ IN UINT8 AcpiTableRevision\r
+ )\r
+{\r
+ UINT32 Index;\r
+ UINT8* TimerPtr;\r
+\r
+ if (!Trace) {\r
+ return;\r
+ }\r
+\r
+ ParseAcpi (\r
+ TRUE,\r
+ 0,\r
+ "GTDT",\r
+ Ptr,\r
+ AcpiTableLength,\r
+ PARSER_PARAMS (GtdtParser)\r
+ );\r
+\r
+ if (*GtdtPlatformTimerCount != 0) {\r
+ TimerPtr = Ptr + (*GtdtPlatformTimerOffset);\r
+ Index = 0;\r
+ do {\r
+ // Parse the Platform Timer Header\r
+ ParseAcpi (\r
+ FALSE,\r
+ 0,\r
+ NULL,\r
+ TimerPtr,\r
+ 4, // GT Platform Timer structure header length.\r
+ PARSER_PARAMS (GtPlatformTimerHeaderParser)\r
+ );\r
+ switch (*PlatformTimerType) {\r
+ case EFI_ACPI_6_2_GTDT_GT_BLOCK:\r
+ DumpGTBlock (TimerPtr, *PlatformTimerLength);\r
+ break;\r
+ case EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG:\r
+ DumpWatchdogTimer (TimerPtr, *PlatformTimerLength);\r
+ break;\r
+ default:\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: INVALID Platform Timer Type = %d\n",\r
+ *PlatformTimerType\r
+ );\r
+ break;\r
+ } // switch\r
+ TimerPtr += (*PlatformTimerLength);\r
+ Index++;\r
+ } while (Index < *GtdtPlatformTimerCount);\r
+ }\r
+}\r