]> git.proxmox.com Git - mirror_edk2.git/blobdiff - DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c
DynamicTablesPkg: Arm ACPI GTDT Generator
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiGtdtLibArm / GtdtGenerator.c
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c b/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c
new file mode 100644 (file)
index 0000000..70f5250
--- /dev/null
@@ -0,0 +1,700 @@
+/** @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
+               &GTBlockTimerFrameList,\r
+               &GTBlockTimerFrameCount\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
+             &GTBlockInfo,\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