--- /dev/null
+/** @file\r
+ GTDT Table Generator\r
+\r
+ Copyright (c) 2017 - 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
+\r
+#include <Library/AcpiLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Protocol/AcpiTable.h>\r
+\r
+// Module specific include files.\r
+#include <AcpiTableGenerator.h>\r
+#include <ConfigurationManagerObject.h>\r
+#include <ConfigurationManagerHelper.h>\r
+#include <Library/TableHelperLib.h>\r
+#include <Protocol/ConfigurationManagerProtocol.h>\r
+\r
+/** ARM standard GTDT Generator\r
+\r
+Requirements:\r
+ The following Configuration Manager Object(s) are required by\r
+ this Generator:\r
+ - EArmObjGenericTimerInfo\r
+ - EArmObjPlatformGenericWatchdogInfo (OPTIONAL)\r
+ - EArmObjPlatformGTBlockInfo (OPTIONAL)\r
+ - EArmObjGTBlockTimerFrameInfo (OPTIONAL)\r
+*/\r
+\r
+/** This macro expands to a function that retrieves the Generic\r
+ Timer Information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjGenericTimerInfo,\r
+ CM_ARM_GENERIC_TIMER_INFO\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the SBSA Generic\r
+ Watchdog Timer Information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjPlatformGenericWatchdogInfo,\r
+ CM_ARM_GENERIC_WATCHDOG_INFO\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the Platform Generic\r
+ Timer Block Information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjPlatformGTBlockInfo,\r
+ CM_ARM_GTBLOCK_INFO\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the Generic\r
+ Timer Block Timer Frame Information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjGTBlockTimerFrameInfo,\r
+ CM_ARM_GTBLOCK_TIMER_FRAME_INFO\r
+ );\r
+\r
+/** Add the Generic Timer Information to the GTDT table.\r
+\r
+ Also update the Platform Timer offset information if the platform\r
+ implements platform timers.\r
+\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [in] Gtdt Pointer to the GTDT Table.\r
+ @param [in] PlatformTimerCount Platform timer count.\r
+\r
+ @retval EFI_SUCCESS Success.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The required object was not found.\r
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration\r
+ Manager is less than the Object size for the\r
+ requested object.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+AddGenericTimerInfo (\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ IN EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE * CONST Gtdt,\r
+ IN CONST UINT32 PlatformTimerCount\r
+)\r
+{\r
+ EFI_STATUS Status;\r
+ CM_ARM_GENERIC_TIMER_INFO * GenericTimerInfo;\r
+\r
+ ASSERT (CfgMgrProtocol != NULL);\r
+ ASSERT (Gtdt != NULL);\r
+\r
+ Status = GetEArmObjGenericTimerInfo (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ &GenericTimerInfo,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: GTDT: Failed to get GenericTimerInfo. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+\r
+ Gtdt->CntControlBasePhysicalAddress =\r
+ GenericTimerInfo->CounterControlBaseAddress;\r
+ Gtdt->Reserved = EFI_ACPI_RESERVED_DWORD;\r
+ Gtdt->SecurePL1TimerGSIV = GenericTimerInfo->SecurePL1TimerGSIV;\r
+ Gtdt->SecurePL1TimerFlags = GenericTimerInfo->SecurePL1TimerFlags;\r
+ Gtdt->NonSecurePL1TimerGSIV = GenericTimerInfo->NonSecurePL1TimerGSIV;\r
+ Gtdt->NonSecurePL1TimerFlags = GenericTimerInfo->NonSecurePL1TimerFlags;\r
+ Gtdt->VirtualTimerGSIV = GenericTimerInfo->VirtualTimerGSIV;\r
+ Gtdt->VirtualTimerFlags = GenericTimerInfo->VirtualTimerFlags;\r
+ Gtdt->NonSecurePL2TimerGSIV = GenericTimerInfo->NonSecurePL2TimerGSIV;\r
+ Gtdt->NonSecurePL2TimerFlags = GenericTimerInfo->NonSecurePL2TimerFlags;\r
+ Gtdt->CntReadBasePhysicalAddress =\r
+ GenericTimerInfo->CounterReadBaseAddress;\r
+ Gtdt->PlatformTimerCount = PlatformTimerCount;\r
+ Gtdt->PlatformTimerOffset = (PlatformTimerCount == 0) ? 0 :\r
+ sizeof (EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Add the SBSA Generic Watchdog Timers to the GTDT table.\r
+\r
+ @param [in] Gtdt Pointer to the GTDT Table.\r
+ @param [in] WatchdogOffset Offset to the watchdog information in the\r
+ GTDT Table.\r
+ @param [in] WatchdogInfoList Pointer to the watchdog information list.\r
+ @param [in] WatchdogCount Platform timer count.\r
+**/\r
+STATIC\r
+VOID\r
+AddGenericWatchdogList (\r
+ IN EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE * CONST Gtdt,\r
+ IN CONST UINT32 WatchdogOffset,\r
+ IN CONST CM_ARM_GENERIC_WATCHDOG_INFO * WatchdogInfoList,\r
+ IN UINT32 WatchdogCount\r
+ )\r
+{\r
+ EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE * Watchdog;\r
+\r
+ ASSERT (Gtdt != NULL);\r
+ ASSERT (WatchdogInfoList != NULL);\r
+\r
+ Watchdog = (EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE *)\r
+ ((UINT8*)Gtdt + WatchdogOffset);\r
+\r
+ while (WatchdogCount-- != 0) {\r
+ // Add watchdog entry\r
+ DEBUG ((DEBUG_INFO, "GTDT: Watchdog = 0x%p\n", Watchdog));\r
+ Watchdog->Type = EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG;\r
+ Watchdog->Length =\r
+ sizeof (EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE);\r
+ Watchdog->Reserved = EFI_ACPI_RESERVED_BYTE;\r
+ Watchdog->RefreshFramePhysicalAddress =\r
+ WatchdogInfoList->RefreshFrameAddress;\r
+ Watchdog->WatchdogControlFramePhysicalAddress =\r
+ WatchdogInfoList->ControlFrameAddress;\r
+ Watchdog->WatchdogTimerGSIV = WatchdogInfoList->TimerGSIV;\r
+ Watchdog->WatchdogTimerFlags = WatchdogInfoList->Flags;\r
+ Watchdog++;\r
+ WatchdogInfoList++;\r
+ } // for\r
+}\r
+\r
+/** Update the GT Block Timer Frame lists in the GTDT Table.\r
+\r
+ @param [in] GtBlockFrame Pointer to the GT Block Frames\r
+ list to be updated.\r
+ @param [in] GTBlockTimerFrameList Pointer to the GT Block Frame\r
+ Information List.\r
+ @param [in] GTBlockFrameCount Number of GT Block Frames.\r
+\r
+ @retval EFI_SUCCESS Table generated successfully.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+AddGTBlockTimerFrames (\r
+ IN EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE * GtBlockFrame,\r
+ IN CONST CM_ARM_GTBLOCK_TIMER_FRAME_INFO * GTBlockTimerFrameList,\r
+ IN UINT32 GTBlockFrameCount\r
+)\r
+{\r
+ ASSERT (GtBlockFrame != NULL);\r
+ ASSERT (GTBlockTimerFrameList != NULL);\r
+\r
+ if (GTBlockFrameCount > 8) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: GTDT: GT Block Frame Count %d is greater than 8\n",\r
+ GTBlockFrameCount\r
+ ));\r
+ ASSERT (GTBlockFrameCount <= 8);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ while (GTBlockFrameCount-- != 0) {\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "GTDT: GtBlockFrame = 0x%p\n",\r
+ GtBlockFrame\r
+ ));\r
+\r
+ GtBlockFrame->GTFrameNumber = GTBlockTimerFrameList->FrameNumber;\r
+ GtBlockFrame->Reserved[0] = EFI_ACPI_RESERVED_BYTE;\r
+ GtBlockFrame->Reserved[1] = EFI_ACPI_RESERVED_BYTE;\r
+ GtBlockFrame->Reserved[2] = EFI_ACPI_RESERVED_BYTE;\r
+\r
+ GtBlockFrame->CntBaseX = GTBlockTimerFrameList->PhysicalAddressCntBase;\r
+ GtBlockFrame->CntEL0BaseX =\r
+ GTBlockTimerFrameList->PhysicalAddressCntEL0Base;\r
+\r
+ GtBlockFrame->GTxPhysicalTimerGSIV =\r
+ GTBlockTimerFrameList->PhysicalTimerGSIV;\r
+ GtBlockFrame->GTxPhysicalTimerFlags =\r
+ GTBlockTimerFrameList->PhysicalTimerFlags;\r
+\r
+ GtBlockFrame->GTxVirtualTimerGSIV = GTBlockTimerFrameList->VirtualTimerGSIV;\r
+ GtBlockFrame->GTxVirtualTimerFlags =\r
+ GTBlockTimerFrameList->VirtualTimerFlags;\r
+\r
+ GtBlockFrame->GTxCommonFlags = GTBlockTimerFrameList->CommonFlags;\r
+ GtBlockFrame++;\r
+ GTBlockTimerFrameList++;\r
+ } // for\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Add the GT Block Timers in the GTDT Table.\r
+\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [in] Gtdt Pointer to the GTDT Table.\r
+ @param [in] GTBlockOffset Offset of the GT Block\r
+ information in the GTDT Table.\r
+ @param [in] GTBlockInfo Pointer to the GT Block\r
+ Information List.\r
+ @param [in] BlockTimerCount Number of GT Block Timers.\r
+\r
+ @retval EFI_SUCCESS Table generated successfully.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+AddGTBlockList (\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ IN EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE * CONST Gtdt,\r
+ IN CONST UINT32 GTBlockOffset,\r
+ IN CONST CM_ARM_GTBLOCK_INFO * GTBlockInfo,\r
+ IN UINT32 BlockTimerCount\r
+)\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE * GTBlock;\r
+ EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE * GtBlockFrame;\r
+ CM_ARM_GTBLOCK_TIMER_FRAME_INFO * GTBlockTimerFrameList;\r
+ UINT32 GTBlockTimerFrameCount;\r
+\r
+ ASSERT (Gtdt != NULL);\r
+ ASSERT (GTBlockInfo != NULL);\r
+\r
+ GTBlock = (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE *)((UINT8*)Gtdt +\r
+ GTBlockOffset);\r
+\r
+ while (BlockTimerCount-- != 0) {\r
+ DEBUG ((DEBUG_INFO, "GTDT: GTBlock = 0x%p\n", GTBlock));\r
+\r
+ Status = GetEArmObjGTBlockTimerFrameInfo (\r
+ CfgMgrProtocol,\r
+ GTBlockInfo->GTBlockTimerFrameToken,\r
+ >BlockTimerFrameList,\r
+ >BlockTimerFrameCount\r
+ );\r
+ if (EFI_ERROR (Status) ||\r
+ (GTBlockTimerFrameCount != GTBlockInfo->GTBlockTimerFrameCount)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: GTDT: Failed to get Generic Timer Frames. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+\r
+ GTBlock->Type = EFI_ACPI_6_2_GTDT_GT_BLOCK;\r
+ GTBlock->Length = sizeof (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE) +\r
+ (sizeof (EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE) *\r
+ GTBlockInfo->GTBlockTimerFrameCount);\r
+\r
+ GTBlock->Reserved = EFI_ACPI_RESERVED_BYTE;\r
+ GTBlock->CntCtlBase = GTBlockInfo->GTBlockPhysicalAddress;\r
+ GTBlock->GTBlockTimerCount = GTBlockInfo->GTBlockTimerFrameCount;\r
+ GTBlock->GTBlockTimerOffset =\r
+ sizeof (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE);\r
+\r
+ GtBlockFrame = (EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE*)\r
+ ((UINT8*)GTBlock + GTBlock->GTBlockTimerOffset);\r
+\r
+ // Add GT Block Timer frames\r
+ Status = AddGTBlockTimerFrames (\r
+ GtBlockFrame,\r
+ GTBlockTimerFrameList,\r
+ GTBlockTimerFrameCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: GTDT: Failed to add Generic Timer Frames. Status = %r\n",\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+\r
+ // Next GTBlock\r
+ GTBlock = (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE *)((UINT8*)GTBlock +\r
+ GTBlock->Length);\r
+ GTBlockInfo++;\r
+ }// for\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Construct the GTDT ACPI table.\r
+\r
+ Called by the Dynamic Table Manager, this function invokes the\r
+ Configuration Manager protocol interface to get the required hardware\r
+ information for generating the ACPI table.\r
+\r
+ If this function allocates any resources then they must be freed\r
+ in the FreeXXXXTableResources function.\r
+\r
+ @param [in] This Pointer to the table generator.\r
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [out] Table Pointer to the constructed ACPI Table.\r
+\r
+ @retval EFI_SUCCESS Table generated successfully.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The required object was not found.\r
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration\r
+ Manager is less than the Object size for the\r
+ requested object.\r
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+BuildGtdtTable (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 TableSize;\r
+ UINT32 PlatformTimerCount;\r
+ UINT32 WatchdogCount;\r
+ UINT32 BlockTimerCount;\r
+ CM_ARM_GENERIC_WATCHDOG_INFO * WatchdogInfoList;\r
+ CM_ARM_GTBLOCK_INFO * GTBlockInfo;\r
+ EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE * Gtdt;\r
+ UINT32 Idx;\r
+ UINT32 GTBlockOffset;\r
+ UINT32 WatchdogOffset;\r
+\r
+ ASSERT (This != NULL);\r
+ ASSERT (AcpiTableInfo != NULL);\r
+ ASSERT (CfgMgrProtocol != NULL);\r
+ ASSERT (Table != NULL);\r
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
+\r
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||\r
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: GTDT: Requested table revision = %d, is not supported."\r
+ "Supported table revision: Minimum = %d, Maximum = %d\n",\r
+ AcpiTableInfo->AcpiTableRevision,\r
+ This->MinAcpiTableRevision,\r
+ This->AcpiTableRevision\r
+ ));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *Table = NULL;\r
+ Status = GetEArmObjPlatformGTBlockInfo (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ >BlockInfo,\r
+ &BlockTimerCount\r
+ );\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: GTDT: Failed to Get Platform GT Block Information." \\r
+ " Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ Status = GetEArmObjPlatformGenericWatchdogInfo (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ &WatchdogInfoList,\r
+ &WatchdogCount\r
+ );\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: GTDT: Failed to Get Platform Generic Watchdog Information." \\r
+ " Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "GTDT: BlockTimerCount = %d, WatchdogCount = %d\n",\r
+ BlockTimerCount,\r
+ WatchdogCount\r
+ ));\r
+\r
+ // Calculate the GTDT Table Size\r
+ PlatformTimerCount = 0;\r
+ TableSize = sizeof (EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE);\r
+ if (BlockTimerCount != 0) {\r
+ GTBlockOffset = TableSize;\r
+ PlatformTimerCount += BlockTimerCount;\r
+ TableSize += (sizeof (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE) *\r
+ BlockTimerCount);\r
+\r
+ for (Idx = 0; Idx < BlockTimerCount; Idx++) {\r
+ if (GTBlockInfo[Idx].GTBlockTimerFrameCount > 8) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "GTDT: GTBockFrameCount cannot be more than 8." \\r
+ " GTBockFrameCount = %d, Status = %r\n",\r
+ GTBlockInfo[Idx].GTBlockTimerFrameCount,\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+ TableSize += (sizeof (EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE) *\r
+ GTBlockInfo[Idx].GTBlockTimerFrameCount);\r
+ }\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "GTDT: GTBockOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",\r
+ GTBlockOffset,\r
+ PlatformTimerCount\r
+ ));\r
+ }\r
+\r
+ WatchdogOffset = 0;\r
+ if (WatchdogCount != 0) {\r
+ WatchdogOffset = TableSize;\r
+ PlatformTimerCount += WatchdogCount;\r
+ TableSize += (sizeof (EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE) *\r
+ WatchdogCount);\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "GTDT: WatchdogOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",\r
+ WatchdogOffset,\r
+ PlatformTimerCount\r
+ ));\r
+ }\r
+\r
+ *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);\r
+ if (*Table == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: GTDT: Failed to allocate memory for GTDT Table, Size = %d," \\r
+ " Status = %r\n",\r
+ TableSize,\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ Gtdt = (EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE*)*Table;\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "GTDT: Gtdt = 0x%p TableSize = 0x%x\n",\r
+ Gtdt,\r
+ TableSize\r
+ ));\r
+\r
+ Status = AddAcpiHeader (\r
+ CfgMgrProtocol,\r
+ This,\r
+ &Gtdt->Header,\r
+ AcpiTableInfo->AcpiTableRevision,\r
+ TableSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: GTDT: Failed to add ACPI header. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ Status = AddGenericTimerInfo (\r
+ CfgMgrProtocol,\r
+ Gtdt,\r
+ PlatformTimerCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: GTDT: Failed to add Generic Timer Info. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ if (BlockTimerCount != 0) {\r
+ Status = AddGTBlockList (\r
+ CfgMgrProtocol,\r
+ Gtdt,\r
+ GTBlockOffset,\r
+ GTBlockInfo,\r
+ BlockTimerCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: GTDT: Failed to add GT Block timers. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+ }\r
+\r
+ if (WatchdogCount != 0) {\r
+ AddGenericWatchdogList (\r
+ Gtdt,\r
+ WatchdogOffset,\r
+ WatchdogInfoList,\r
+ WatchdogCount\r
+ );\r
+ }\r
+\r
+ return Status;\r
+\r
+error_handler:\r
+ if (*Table != NULL) {\r
+ FreePool (*Table);\r
+ *Table = NULL;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/** Free any resources allocated for constructing the GTDT.\r
+\r
+ @param [in] This Pointer to the table generator.\r
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [in, out] Table Pointer to the ACPI Table.\r
+\r
+ @retval EFI_SUCCESS The resources were freed successfully.\r
+ @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+FreeGtdtTableResources (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table\r
+)\r
+{\r
+ ASSERT (This != NULL);\r
+ ASSERT (AcpiTableInfo != NULL);\r
+ ASSERT (CfgMgrProtocol != NULL);\r
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
+\r
+ if ((Table == NULL) || (*Table == NULL)) {\r
+ DEBUG ((DEBUG_ERROR, "ERROR: GTDT: Invalid Table Pointer\n"));\r
+ ASSERT ((Table != NULL) && (*Table != NULL));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ FreePool (*Table);\r
+ *Table = NULL;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** This macro defines the GTDT Table Generator revision.\r
+*/\r
+#define GTDT_GENERATOR_REVISION CREATE_REVISION (1, 0)\r
+\r
+/** The interface for the GTDT Table Generator.\r
+*/\r
+STATIC\r
+CONST\r
+ACPI_TABLE_GENERATOR GtdtGenerator = {\r
+ // Generator ID\r
+ CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdGtdt),\r
+ // Generator Description\r
+ L"ACPI.STD.GTDT.GENERATOR",\r
+ // ACPI Table Signature\r
+ EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE,\r
+ // ACPI Table Revision supported by this Generator\r
+ EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION,\r
+ // Minimum ACPI Table Revision supported by this Generator\r
+ EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION,\r
+ // Creator ID\r
+ TABLE_GENERATOR_CREATOR_ID_ARM,\r
+ // Creator Revision\r
+ GTDT_GENERATOR_REVISION,\r
+ // Build Table function\r
+ BuildGtdtTable,\r
+ // Free Resource function\r
+ FreeGtdtTableResources,\r
+ // Extended build function not needed\r
+ NULL,\r
+ // Extended build function not implemented by the generator.\r
+ // Hence extended free resource function is not required.\r
+ NULL\r
+};\r
+\r
+/** Register the Generator with the ACPI Table Factory.\r
+\r
+ @param [in] ImageHandle The handle to the image.\r
+ @param [in] SystemTable Pointer to the System Table.\r
+\r
+ @retval EFI_SUCCESS The Generator is registered.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_ALREADY_STARTED The Generator for the Table ID\r
+ is already registered.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AcpiGtdtLibConstructor (\r
+ IN CONST EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE * CONST SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ Status = RegisterAcpiTableGenerator (&GtdtGenerator);\r
+ DEBUG ((DEBUG_INFO, "GTDT: Register Generator. Status = %r\n", Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+}\r
+\r
+/** Deregister the Generator from the ACPI Table Factory.\r
+\r
+ @param [in] ImageHandle The handle to the image.\r
+ @param [in] SystemTable Pointer to the System Table.\r
+\r
+ @retval EFI_SUCCESS The Generator is deregistered.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The Generator is not registered.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AcpiGtdtLibDestructor (\r
+ IN CONST EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE * CONST SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ Status = DeregisterAcpiTableGenerator (&GtdtGenerator);\r
+ DEBUG ((DEBUG_INFO, "GTDT: Deregister Generator. Status = %r\n", Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+}\r