mirror of https://github.com/acidanthera/audk.git
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;
|
|
}
|