Removing GT Block frame count check from AddGTBlockTimerFrames() as this is already validated in BuildGtdtTable(). Signed-off-by: Sami Mujawar <sami.mujawar@arm.com> Reviewed-by: Alexei Fedorov <Alexei.Fedorov@arm.com>
		
			
				
	
	
		
			781 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			781 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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,
 | 
						|
               >BlockTimerFrameList,
 | 
						|
               >BlockTimerFrameCount
 | 
						|
               );
 | 
						|
    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,
 | 
						|
             >BlockInfo,
 | 
						|
             &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;
 | 
						|
}
 |