/** @file\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
+ Copyright (c) 2016 - 2020, ARM Limited. All rights reserved.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
@par Reference(s):\r
- - ACPI 6.2 Specification - Errata A, September 2017\r
+ - ACPI 6.3 Specification - January 2019\r
**/\r
\r
#include <IndustryStandard/Acpi.h>\r
#include <Library/UefiLib.h>\r
#include "AcpiParser.h"\r
#include "AcpiTableParser.h"\r
+#include "AcpiViewConfig.h"\r
+\r
+// "The number of GT Block Timers must be less than or equal to 8"\r
+#define GT_BLOCK_TIMER_COUNT_MAX 8\r
\r
// Local variables\r
STATIC CONST UINT32* GtdtPlatformTimerCount;\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
/**\r
ValidateGtBlockTimerCount (\r
IN UINT8* Ptr,\r
IN VOID* Context\r
- );\r
+ )\r
+{\r
+ UINT32 BlockTimerCount;\r
+\r
+ BlockTimerCount = *(UINT32*)Ptr;\r
+\r
+ if (BlockTimerCount > GT_BLOCK_TIMER_COUNT_MAX) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"\nERROR: Timer Count = %d. Max Timer Count is %d.",\r
+ BlockTimerCount,\r
+ GT_BLOCK_TIMER_COUNT_MAX\r
+ );\r
+ }\r
+}\r
+\r
+/**\r
+ This function validates the GT Frame Number.\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
+ValidateGtFrameNumber (\r
+ IN UINT8* Ptr,\r
+ IN VOID* Context\r
+ )\r
+{\r
+ UINT8 FrameNumber;\r
+\r
+ FrameNumber = *(UINT8*)Ptr;\r
+\r
+ if (FrameNumber >= GT_BLOCK_TIMER_COUNT_MAX) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"\nERROR: GT Frame Number = %d. GT Frame Number must be in range 0-%d.",\r
+ FrameNumber,\r
+ GT_BLOCK_TIMER_COUNT_MAX - 1\r
+ );\r
+ }\r
+}\r
\r
/**\r
An ACPI_PARSER array describing the ACPI GTDT Table.\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
+ (VOID**)&GtdtPlatformTimerOffset, NULL, NULL},\r
+ {L"Virtual EL2 Timer GSIV", 4, 96, L"0x%x", NULL, NULL, NULL, NULL},\r
+ {L"Virtual EL2 Timer Flags", 4, 100, L"0x%x", NULL, NULL, NULL, NULL}\r
};\r
\r
/**\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"Length", 2, 1, L"%d", NULL, NULL, 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
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"Frame Number", 1, 0, L"%d", NULL, NULL, ValidateGtFrameNumber, 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
};\r
\r
/**\r
- This function validates the GT Block timer count.\r
+ This function parses the Platform GT Block.\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
+ @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
-EFIAPI\r
-ValidateGtBlockTimerCount (\r
+DumpGTBlock (\r
IN UINT8* Ptr,\r
- IN VOID* Context\r
+ IN UINT16 Length\r
)\r
{\r
- UINT32 BlockTimerCount;\r
+ UINT32 Index;\r
+ UINT32 Offset;\r
\r
- BlockTimerCount = *(UINT32*)Ptr;\r
+ ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "GT Block",\r
+ Ptr,\r
+ Length,\r
+ PARSER_PARAMS (GtBlockParser)\r
+ );\r
\r
- if (BlockTimerCount > 8) {\r
+ // Check if the values used to control the parsing logic have been\r
+ // successfully read.\r
+ if ((GtBlockTimerCount == NULL) ||\r
+ (GtBlockTimerOffset == NULL)) {\r
IncrementErrorCount ();\r
Print (\r
- L"\nERROR: Timer Count = %d. Max Timer Count is 8.",\r
- BlockTimerCount\r
+ L"ERROR: Insufficient GT Block Structure length. Length = %d.\n",\r
+ Length\r
);\r
+ return;\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
+ Offset = *GtBlockTimerOffset;\r
+ Index = 0;\r
+\r
+ // Parse the specified number of GT Block Timer Structures or the GT Block\r
+ // Structure buffer length. Whichever is minimum.\r
+ while ((Index++ < *GtBlockTimerCount) &&\r
+ (Offset < Length)) {\r
+ Offset += ParseAcpi (\r
+ TRUE,\r
+ 2,\r
+ "GT Block Timer",\r
+ Ptr + Offset,\r
+ Length - Offset,\r
+ PARSER_PARAMS (GtBlockTimerParser)\r
+ );\r
}\r
}\r
\r
)\r
{\r
UINT32 Index;\r
+ UINT32 Offset;\r
UINT8* TimerPtr;\r
\r
if (!Trace) {\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
+ // Check if the values used to control the parsing logic have been\r
+ // successfully read.\r
+ if ((GtdtPlatformTimerCount == NULL) ||\r
+ (GtdtPlatformTimerOffset == NULL)) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Insufficient table length. AcpiTableLength = %d.\n",\r
+ AcpiTableLength\r
+ );\r
+ return;\r
}\r
+\r
+ TimerPtr = Ptr + *GtdtPlatformTimerOffset;\r
+ Offset = *GtdtPlatformTimerOffset;\r
+ Index = 0;\r
+\r
+ // Parse the specified number of Platform Timer Structures or the GTDT\r
+ // buffer length. Whichever is minimum.\r
+ while ((Index++ < *GtdtPlatformTimerCount) &&\r
+ (Offset < AcpiTableLength)) {\r
+ // Parse the Platform Timer Header to obtain Length and Type\r
+ ParseAcpi (\r
+ FALSE,\r
+ 0,\r
+ NULL,\r
+ TimerPtr,\r
+ AcpiTableLength - Offset,\r
+ PARSER_PARAMS (GtPlatformTimerHeaderParser)\r
+ );\r
+\r
+ // Check if the values used to control the parsing logic have been\r
+ // successfully read.\r
+ if ((PlatformTimerType == NULL) ||\r
+ (PlatformTimerLength == NULL)) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Insufficient remaining table buffer length to read the " \\r
+ L"Platform Timer Structure header. Length = %d.\n",\r
+ AcpiTableLength - Offset\r
+ );\r
+ return;\r
+ }\r
+\r
+ // Validate Platform Timer Structure length\r
+ if ((*PlatformTimerLength == 0) ||\r
+ ((Offset + (*PlatformTimerLength)) > AcpiTableLength)) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Invalid Platform Timer Structure length. " \\r
+ L"Length = %d. Offset = %d. AcpiTableLength = %d.\n",\r
+ *PlatformTimerLength,\r
+ Offset,\r
+ AcpiTableLength\r
+ );\r
+ return;\r
+ }\r
+\r
+ switch (*PlatformTimerType) {\r
+ case EFI_ACPI_6_3_GTDT_GT_BLOCK:\r
+ DumpGTBlock (TimerPtr, *PlatformTimerLength);\r
+ break;\r
+ case EFI_ACPI_6_3_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
+\r
+ TimerPtr += *PlatformTimerLength;\r
+ Offset += *PlatformTimerLength;\r
+ } // while\r
}\r