summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c780
1 files changed, 780 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c
new file mode 100644
index 00000000..27dccab5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c
@@ -0,0 +1,780 @@
+/** @file
+ GTDT Table Generator
+
+ Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - ACPI 6.3 Specification - January 2019
+
+**/
+
+#include <Library/AcpiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/AcpiTable.h>
+
+// Module specific include files.
+#include <AcpiTableGenerator.h>
+#include <ConfigurationManagerObject.h>
+#include <ConfigurationManagerHelper.h>
+#include <Library/TableHelperLib.h>
+#include <Protocol/ConfigurationManagerProtocol.h>
+
+/** ARM standard GTDT Generator
+
+Requirements:
+ The following Configuration Manager Object(s) are required by
+ this Generator:
+ - EArmObjGenericTimerInfo
+ - EArmObjPlatformGenericWatchdogInfo (OPTIONAL)
+ - EArmObjPlatformGTBlockInfo (OPTIONAL)
+ - EArmObjGTBlockTimerFrameInfo (OPTIONAL)
+*/
+
+/** This macro expands to a function that retrieves the Generic
+ Timer Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjGenericTimerInfo,
+ CM_ARM_GENERIC_TIMER_INFO
+ );
+
+/** This macro expands to a function that retrieves the SBSA Generic
+ Watchdog Timer Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPlatformGenericWatchdogInfo,
+ CM_ARM_GENERIC_WATCHDOG_INFO
+ );
+
+/** This macro expands to a function that retrieves the Platform Generic
+ Timer Block Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPlatformGTBlockInfo,
+ CM_ARM_GTBLOCK_INFO
+ );
+
+/** This macro expands to a function that retrieves the Generic
+ Timer Block Timer Frame Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjGTBlockTimerFrameInfo,
+ CM_ARM_GTBLOCK_TIMER_FRAME_INFO
+ );
+
+/** Add the Generic Timer Information to the GTDT table.
+
+ Also update the Platform Timer offset information if the platform
+ implements platform timers.
+
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Gtdt Pointer to the GTDT Table.
+ @param [in] PlatformTimerCount Platform timer count.
+ @param [in] AcpiTableRevision Acpi Revision targeted by the platform.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
+ Manager is less than the Object size for the
+ requested object.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AddGenericTimerInfo (
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE * CONST Gtdt,
+ IN CONST UINT32 PlatformTimerCount,
+ IN CONST UINT32 AcpiTableRevision
+)
+{
+ EFI_STATUS Status;
+ CM_ARM_GENERIC_TIMER_INFO * GenericTimerInfo;
+
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (Gtdt != NULL);
+
+ Status = GetEArmObjGenericTimerInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &GenericTimerInfo,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Failed to get GenericTimerInfo. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ Gtdt->CntControlBasePhysicalAddress =
+ GenericTimerInfo->CounterControlBaseAddress;
+ Gtdt->Reserved = EFI_ACPI_RESERVED_DWORD;
+ Gtdt->SecurePL1TimerGSIV = GenericTimerInfo->SecurePL1TimerGSIV;
+ Gtdt->SecurePL1TimerFlags = GenericTimerInfo->SecurePL1TimerFlags;
+ Gtdt->NonSecurePL1TimerGSIV = GenericTimerInfo->NonSecurePL1TimerGSIV;
+ Gtdt->NonSecurePL1TimerFlags = GenericTimerInfo->NonSecurePL1TimerFlags;
+ Gtdt->VirtualTimerGSIV = GenericTimerInfo->VirtualTimerGSIV;
+ Gtdt->VirtualTimerFlags = GenericTimerInfo->VirtualTimerFlags;
+ Gtdt->NonSecurePL2TimerGSIV = GenericTimerInfo->NonSecurePL2TimerGSIV;
+ Gtdt->NonSecurePL2TimerFlags = GenericTimerInfo->NonSecurePL2TimerFlags;
+ Gtdt->CntReadBasePhysicalAddress =
+ GenericTimerInfo->CounterReadBaseAddress;
+ Gtdt->PlatformTimerCount = PlatformTimerCount;
+ Gtdt->PlatformTimerOffset = (PlatformTimerCount == 0) ? 0 :
+ sizeof (EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE);
+
+ if (AcpiTableRevision > EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION) {
+ Gtdt->VirtualPL2TimerGSIV = GenericTimerInfo->VirtualPL2TimerGSIV;
+ Gtdt->VirtualPL2TimerFlags = GenericTimerInfo->VirtualPL2TimerFlags;
+ }
+
+ return Status;
+}
+
+/** Add the SBSA Generic Watchdog Timers to the GTDT table.
+
+ @param [in] Gtdt Pointer to the GTDT Table.
+ @param [in] WatchdogOffset Offset to the watchdog information in the
+ GTDT Table.
+ @param [in] WatchdogInfoList Pointer to the watchdog information list.
+ @param [in] WatchdogCount Platform timer count.
+**/
+STATIC
+VOID
+AddGenericWatchdogList (
+ IN EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE * CONST Gtdt,
+ IN CONST UINT32 WatchdogOffset,
+ IN CONST CM_ARM_GENERIC_WATCHDOG_INFO * WatchdogInfoList,
+ IN UINT32 WatchdogCount
+ )
+{
+ EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE * Watchdog;
+
+ ASSERT (Gtdt != NULL);
+ ASSERT (WatchdogInfoList != NULL);
+
+ Watchdog = (EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE *)
+ ((UINT8*)Gtdt + WatchdogOffset);
+
+ while (WatchdogCount-- != 0) {
+ // Add watchdog entry
+ DEBUG ((DEBUG_INFO, "GTDT: Watchdog = 0x%p\n", Watchdog));
+ Watchdog->Type = EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG;
+ Watchdog->Length =
+ sizeof (EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE);
+ Watchdog->Reserved = EFI_ACPI_RESERVED_BYTE;
+ Watchdog->RefreshFramePhysicalAddress =
+ WatchdogInfoList->RefreshFrameAddress;
+ Watchdog->WatchdogControlFramePhysicalAddress =
+ WatchdogInfoList->ControlFrameAddress;
+ Watchdog->WatchdogTimerGSIV = WatchdogInfoList->TimerGSIV;
+ Watchdog->WatchdogTimerFlags = WatchdogInfoList->Flags;
+ Watchdog++;
+ WatchdogInfoList++;
+ } // for
+}
+
+/**
+ Function to test if two Generic Timer Block Frame Info structures have the
+ same frame number.
+
+ @param [in] Frame1 Pointer to the first GT Block Frame Info
+ structure.
+ @param [in] Frame2 Pointer to the second GT Block Frame Info
+ structure.
+ @param [in] Index1 Index of Frame1 in the shared GT Block Frame
+ Information List.
+ @param [in] Index2 Index of Frame2 in the shared GT Block Frame
+ Information List.
+
+ @retval TRUE Frame1 and Frame2 have the same frame number.
+ @return FALSE Frame1 and Frame2 have different frame numbers.
+
+**/
+BOOLEAN
+EFIAPI
+IsGtFrameNumberEqual (
+ IN CONST VOID * Frame1,
+ IN CONST VOID * Frame2,
+ IN UINTN Index1,
+ IN UINTN Index2
+ )
+{
+ UINT8 FrameNumber1;
+ UINT8 FrameNumber2;
+
+ ASSERT ((Frame1 != NULL) && (Frame2 != NULL));
+
+ FrameNumber1 = ((CM_ARM_GTBLOCK_TIMER_FRAME_INFO*)Frame1)->FrameNumber;
+ FrameNumber2 = ((CM_ARM_GTBLOCK_TIMER_FRAME_INFO*)Frame2)->FrameNumber;
+
+ if (FrameNumber1 == FrameNumber2) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: GT Block Frame Info Structures %d and %d have the same " \
+ "frame number: 0x%x.\n",
+ Index1,
+ Index2,
+ FrameNumber1
+ ));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/** Update the GT Block Timer Frame lists in the GTDT Table.
+
+ @param [in] GtBlockFrame Pointer to the GT Block Frames
+ list to be updated.
+ @param [in] GTBlockTimerFrameList Pointer to the GT Block Frame
+ Information List.
+ @param [in] GTBlockFrameCount Number of GT Block Frames.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+**/
+STATIC
+EFI_STATUS
+AddGTBlockTimerFrames (
+ IN EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE * GtBlockFrame,
+ IN CONST CM_ARM_GTBLOCK_TIMER_FRAME_INFO * GTBlockTimerFrameList,
+ IN UINT32 GTBlockFrameCount
+)
+{
+ BOOLEAN IsFrameNumberDuplicated;
+
+ ASSERT (GtBlockFrame != NULL);
+ ASSERT (GTBlockTimerFrameList != NULL);
+
+ IsFrameNumberDuplicated = FindDuplicateValue (
+ GTBlockTimerFrameList,
+ GTBlockFrameCount,
+ sizeof (CM_ARM_GTBLOCK_TIMER_FRAME_INFO),
+ IsGtFrameNumberEqual
+ );
+ // Duplicate entry was found so timer frame numbers provided are invalid
+ if (IsFrameNumberDuplicated) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ while (GTBlockFrameCount-- != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "GTDT: GtBlockFrame = 0x%p\n",
+ GtBlockFrame
+ ));
+
+ if (GTBlockTimerFrameList->FrameNumber >= 8) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Frame number %d is not in the range 0-7\n",
+ GTBlockTimerFrameList->FrameNumber
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GtBlockFrame->GTFrameNumber = GTBlockTimerFrameList->FrameNumber;
+ GtBlockFrame->Reserved[0] = EFI_ACPI_RESERVED_BYTE;
+ GtBlockFrame->Reserved[1] = EFI_ACPI_RESERVED_BYTE;
+ GtBlockFrame->Reserved[2] = EFI_ACPI_RESERVED_BYTE;
+
+ GtBlockFrame->CntBaseX = GTBlockTimerFrameList->PhysicalAddressCntBase;
+ GtBlockFrame->CntEL0BaseX =
+ GTBlockTimerFrameList->PhysicalAddressCntEL0Base;
+
+ GtBlockFrame->GTxPhysicalTimerGSIV =
+ GTBlockTimerFrameList->PhysicalTimerGSIV;
+ GtBlockFrame->GTxPhysicalTimerFlags =
+ GTBlockTimerFrameList->PhysicalTimerFlags;
+
+ GtBlockFrame->GTxVirtualTimerGSIV = GTBlockTimerFrameList->VirtualTimerGSIV;
+ GtBlockFrame->GTxVirtualTimerFlags =
+ GTBlockTimerFrameList->VirtualTimerFlags;
+
+ GtBlockFrame->GTxCommonFlags = GTBlockTimerFrameList->CommonFlags;
+ GtBlockFrame++;
+ GTBlockTimerFrameList++;
+ } // for
+ return EFI_SUCCESS;
+}
+
+/** Add the GT Block Timers in the GTDT Table.
+
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Gtdt Pointer to the GTDT Table.
+ @param [in] GTBlockOffset Offset of the GT Block
+ information in the GTDT Table.
+ @param [in] GTBlockInfo Pointer to the GT Block
+ Information List.
+ @param [in] BlockTimerCount Number of GT Block Timers.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+**/
+STATIC
+EFI_STATUS
+AddGTBlockList (
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE * CONST Gtdt,
+ IN CONST UINT32 GTBlockOffset,
+ IN CONST CM_ARM_GTBLOCK_INFO * GTBlockInfo,
+ IN UINT32 BlockTimerCount
+)
+{
+ EFI_STATUS Status;
+ EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE * GTBlock;
+ EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE * GtBlockFrame;
+ CM_ARM_GTBLOCK_TIMER_FRAME_INFO * GTBlockTimerFrameList;
+ UINT32 GTBlockTimerFrameCount;
+ UINTN Length;
+
+ ASSERT (Gtdt != NULL);
+ ASSERT (GTBlockInfo != NULL);
+
+ GTBlock = (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE *)((UINT8*)Gtdt +
+ GTBlockOffset);
+
+ while (BlockTimerCount-- != 0) {
+ DEBUG ((DEBUG_INFO, "GTDT: GTBlock = 0x%p\n", GTBlock));
+
+ Status = GetEArmObjGTBlockTimerFrameInfo (
+ CfgMgrProtocol,
+ GTBlockInfo->GTBlockTimerFrameToken,
+ &GTBlockTimerFrameList,
+ &GTBlockTimerFrameCount
+ );
+ if (EFI_ERROR (Status) ||
+ (GTBlockTimerFrameCount != GTBlockInfo->GTBlockTimerFrameCount)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Failed to get Generic Timer Frames. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ Length = sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE) +
+ (sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE) *
+ GTBlockInfo->GTBlockTimerFrameCount);
+
+ // Check that the length of the GT block does not
+ // exceed MAX_UINT16
+ if (Length > MAX_UINT16) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Too many GT Frames. Count = %d. " \
+ "Maximum supported GT Block size exceeded. " \
+ "Status = %r\n",
+ GTBlockInfo->GTBlockTimerFrameCount,
+ Status
+ ));
+ return Status;
+ }
+
+ GTBlock->Type = EFI_ACPI_6_3_GTDT_GT_BLOCK;
+ GTBlock->Length = (UINT16)Length;
+ GTBlock->Reserved = EFI_ACPI_RESERVED_BYTE;
+ GTBlock->CntCtlBase = GTBlockInfo->GTBlockPhysicalAddress;
+ GTBlock->GTBlockTimerCount = GTBlockInfo->GTBlockTimerFrameCount;
+ GTBlock->GTBlockTimerOffset =
+ sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE);
+
+ GtBlockFrame = (EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE*)
+ ((UINT8*)GTBlock + GTBlock->GTBlockTimerOffset);
+
+ // Add GT Block Timer frames
+ Status = AddGTBlockTimerFrames (
+ GtBlockFrame,
+ GTBlockTimerFrameList,
+ GTBlockTimerFrameCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Failed to add Generic Timer Frames. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Next GTBlock
+ GTBlock = (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE *)((UINT8*)GTBlock +
+ GTBlock->Length);
+ GTBlockInfo++;
+ }// for
+ return EFI_SUCCESS;
+}
+
+/** Construct the GTDT ACPI table.
+
+ Called by the Dynamic Table Manager, this function invokes the
+ Configuration Manager protocol interface to get the required hardware
+ information for generating the ACPI table.
+
+ If this function allocates any resources then they must be freed
+ in the FreeXXXXTableResources function.
+
+ @param [in] This Pointer to the table generator.
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [out] Table Pointer to the constructed ACPI Table.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
+ Manager is less than the Object size for the
+ requested object.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildGtdtTable (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TableSize;
+ UINT32 PlatformTimerCount;
+ UINT32 WatchdogCount;
+ UINT32 BlockTimerCount;
+ CM_ARM_GENERIC_WATCHDOG_INFO * WatchdogInfoList;
+ CM_ARM_GTBLOCK_INFO * GTBlockInfo;
+ EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE * Gtdt;
+ UINT32 Idx;
+ UINT32 GTBlockOffset;
+ UINT32 WatchdogOffset;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (Table != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Requested table revision = %d, is not supported."
+ "Supported table revision: Minimum = %d, Maximum = %d\n",
+ AcpiTableInfo->AcpiTableRevision,
+ This->MinAcpiTableRevision,
+ This->AcpiTableRevision
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Table = NULL;
+ Status = GetEArmObjPlatformGTBlockInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &GTBlockInfo,
+ &BlockTimerCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Failed to Get Platform GT Block Information." \
+ " Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ Status = GetEArmObjPlatformGenericWatchdogInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &WatchdogInfoList,
+ &WatchdogCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Failed to Get Platform Generic Watchdog Information." \
+ " Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "GTDT: BlockTimerCount = %d, WatchdogCount = %d\n",
+ BlockTimerCount,
+ WatchdogCount
+ ));
+
+ // Calculate the GTDT Table Size
+ PlatformTimerCount = 0;
+ TableSize = sizeof (EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE);
+ if (BlockTimerCount != 0) {
+ GTBlockOffset = TableSize;
+ PlatformTimerCount += BlockTimerCount;
+ TableSize += (sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE) *
+ BlockTimerCount);
+
+ for (Idx = 0; Idx < BlockTimerCount; Idx++) {
+ if (GTBlockInfo[Idx].GTBlockTimerFrameCount > 8) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "GTDT: GTBockFrameCount cannot be more than 8." \
+ " GTBockFrameCount = %d, Status = %r\n",
+ GTBlockInfo[Idx].GTBlockTimerFrameCount,
+ Status
+ ));
+ goto error_handler;
+ }
+ TableSize += (sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE) *
+ GTBlockInfo[Idx].GTBlockTimerFrameCount);
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "GTDT: GTBockOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",
+ GTBlockOffset,
+ PlatformTimerCount
+ ));
+ }
+
+ WatchdogOffset = 0;
+ if (WatchdogCount != 0) {
+ WatchdogOffset = TableSize;
+ PlatformTimerCount += WatchdogCount;
+ TableSize += (sizeof (EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE) *
+ WatchdogCount);
+ DEBUG ((
+ DEBUG_INFO,
+ "GTDT: WatchdogOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",
+ WatchdogOffset,
+ PlatformTimerCount
+ ));
+ }
+
+ *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);
+ if (*Table == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Failed to allocate memory for GTDT Table, Size = %d," \
+ " Status = %r\n",
+ TableSize,
+ Status
+ ));
+ goto error_handler;
+ }
+
+ Gtdt = (EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE*)*Table;
+ DEBUG ((
+ DEBUG_INFO,
+ "GTDT: Gtdt = 0x%p TableSize = 0x%x\n",
+ Gtdt,
+ TableSize
+ ));
+
+ Status = AddAcpiHeader (
+ CfgMgrProtocol,
+ This,
+ &Gtdt->Header,
+ AcpiTableInfo,
+ TableSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Failed to add ACPI header. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ Status = AddGenericTimerInfo (
+ CfgMgrProtocol,
+ Gtdt,
+ PlatformTimerCount,
+ AcpiTableInfo->AcpiTableRevision
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Failed to add Generic Timer Info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ if (BlockTimerCount != 0) {
+ Status = AddGTBlockList (
+ CfgMgrProtocol,
+ Gtdt,
+ GTBlockOffset,
+ GTBlockInfo,
+ BlockTimerCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Failed to add GT Block timers. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ if (WatchdogCount != 0) {
+ AddGenericWatchdogList (
+ Gtdt,
+ WatchdogOffset,
+ WatchdogInfoList,
+ WatchdogCount
+ );
+ }
+
+ return Status;
+
+error_handler:
+ if (*Table != NULL) {
+ FreePool (*Table);
+ *Table = NULL;
+ }
+ return Status;
+}
+
+/** Free any resources allocated for constructing the GTDT.
+
+ @param [in] This Pointer to the table generator.
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in, out] Table Pointer to the ACPI Table.
+
+ @retval EFI_SUCCESS The resources were freed successfully.
+ @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
+**/
+STATIC
+EFI_STATUS
+FreeGtdtTableResources (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table
+)
+{
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ if ((Table == NULL) || (*Table == NULL)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: GTDT: Invalid Table Pointer\n"));
+ ASSERT ((Table != NULL) && (*Table != NULL));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FreePool (*Table);
+ *Table = NULL;
+ return EFI_SUCCESS;
+}
+
+/** This macro defines the GTDT Table Generator revision.
+*/
+#define GTDT_GENERATOR_REVISION CREATE_REVISION (1, 0)
+
+/** The interface for the GTDT Table Generator.
+*/
+STATIC
+CONST
+ACPI_TABLE_GENERATOR GtdtGenerator = {
+ // Generator ID
+ CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdGtdt),
+ // Generator Description
+ L"ACPI.STD.GTDT.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE,
+ // ACPI Table Revision supported by this Generator
+ EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION,
+ // Minimum ACPI Table Revision supported by this Generator
+ EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION,
+ // Creator ID
+ TABLE_GENERATOR_CREATOR_ID_ARM,
+ // Creator Revision
+ GTDT_GENERATOR_REVISION,
+ // Build Table function
+ BuildGtdtTable,
+ // Free Resource function
+ FreeGtdtTableResources,
+ // Extended build function not needed
+ NULL,
+ // Extended build function not implemented by the generator.
+ // Hence extended free resource function is not required.
+ NULL
+};
+
+/** Register the Generator with the ACPI Table Factory.
+
+ @param [in] ImageHandle The handle to the image.
+ @param [in] SystemTable Pointer to the System Table.
+
+ @retval EFI_SUCCESS The Generator is registered.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_ALREADY_STARTED The Generator for the Table ID
+ is already registered.
+**/
+EFI_STATUS
+EFIAPI
+AcpiGtdtLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = RegisterAcpiTableGenerator (&GtdtGenerator);
+ DEBUG ((DEBUG_INFO, "GTDT: Register Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/** Deregister the Generator from the ACPI Table Factory.
+
+ @param [in] ImageHandle The handle to the image.
+ @param [in] SystemTable Pointer to the System Table.
+
+ @retval EFI_SUCCESS The Generator is deregistered.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The Generator is not registered.
+**/
+EFI_STATUS
+EFIAPI
+AcpiGtdtLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&GtdtGenerator);
+ DEBUG ((DEBUG_INFO, "GTDT: Deregister Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}