diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc index f4866c2dd740..bbfc4c20b96d 100644 --- a/DynamicTablesPkg/DynamicTables.dsc.inc +++ b/DynamicTablesPkg/DynamicTables.dsc.inc @@ -56,6 +56,7 @@ # Generators (IA32/X64 specific) # DynamicTablesPkg/Library/Acpi/X64/AcpiWsmtLib/AcpiWsmtLib.inf + DynamicTablesPkg/Library/Acpi/X64/AcpiHpetLib/AcpiHpetLib.inf # # Dynamic Table Factory Dxe @@ -66,6 +67,7 @@ # Common NULL|DynamicTablesPkg/Library/Acpi/Common/AcpiFadtLib/AcpiFadtLib.inf NULL|DynamicTablesPkg/Library/Acpi/X64/AcpiWsmtLib/AcpiWsmtLib.inf + NULL|DynamicTablesPkg/Library/Acpi/X64/AcpiHpetLib/AcpiHpetLib.inf } [Components.ARM, Components.AARCH64] diff --git a/DynamicTablesPkg/DynamicTablesPkg.ci.yaml b/DynamicTablesPkg/DynamicTablesPkg.ci.yaml index 07768ed648ea..f7c8897fcbbe 100644 --- a/DynamicTablesPkg/DynamicTablesPkg.ci.yaml +++ b/DynamicTablesPkg/DynamicTablesPkg.ci.yaml @@ -113,6 +113,7 @@ "lgreater", "lless", "MPIDR", + "NAMESPACEID", "PASID", "PERIPHBASE", "phandle", diff --git a/DynamicTablesPkg/Include/AcpiTableGenerator.h b/DynamicTablesPkg/Include/AcpiTableGenerator.h index d4ad603e2b85..8923fefd54e8 100644 --- a/DynamicTablesPkg/Include/AcpiTableGenerator.h +++ b/DynamicTablesPkg/Include/AcpiTableGenerator.h @@ -105,6 +105,7 @@ typedef enum StdAcpiTableId { EStdAcpiTableIdPcct, ///< PCCT Generator EStdAcpiTableIdTpm2, ///< TPM2 Generator EStdAcpiTableIdWsmt, ///< WSMT Generator + EStdAcpiTableIdHpet, ///< HPET Generator EStdAcpiTableIdMax } ESTD_ACPI_TABLE_ID; diff --git a/DynamicTablesPkg/Include/X64NameSpaceObjects.h b/DynamicTablesPkg/Include/X64NameSpaceObjects.h index d897051d88b6..f153461be0cc 100644 --- a/DynamicTablesPkg/Include/X64NameSpaceObjects.h +++ b/DynamicTablesPkg/Include/X64NameSpaceObjects.h @@ -32,7 +32,8 @@ typedef enum X64ObjectID { EX64ObjFadtResetBlockInfo, ///< 8 - FADT Reset block info EX64ObjFadtMiscInfo, ///< 9 - FADT Legacy fields info EX64ObjWsmtFlagsInfo, ///< 10 - WSMT protection flags info - EX64ObjMax ///< 11 - Maximum Object ID + EX64ObjHpetInfo, ///< 11 - HPET device info + EX64ObjMax ///< 12 - Maximum Object ID } EX64_OBJECT_ID; /** A structure that describes the @@ -177,4 +178,14 @@ typedef struct CmX64WsmtFlagsInfo { UINT32 ProtectionFlags; } CM_X64_WSMT_FLAGS_INFO; +/** + A structure that describes the HPET device information. + + ID: EX64ObjHpetInfo +*/ +typedef struct CmX64HpetInfo { + UINT32 BaseAddressLower32Bit; + UINT16 MainCounterMinimumClockTickInPeriodicMode; + UINT8 PageProtectionAndOemAttribute; +} CM_X64_HPET_INFO; #endif // X64_NAMESPACE_OBJECTS_H_ diff --git a/DynamicTablesPkg/Library/Acpi/X64/AcpiHpetLib/AcpiHpetLib.c b/DynamicTablesPkg/Library/Acpi/X64/AcpiHpetLib/AcpiHpetLib.c new file mode 100644 index 000000000000..b53518dc3129 --- /dev/null +++ b/DynamicTablesPkg/Library/Acpi/X64/AcpiHpetLib/AcpiHpetLib.c @@ -0,0 +1,327 @@ +/** @file + + Generate ACPI HPET table for AMD platforms. + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** This macro defines supported HPET page protection flags +*/ +#define HPET_VALID_PAGE_PROTECTION \ + (EFI_ACPI_NO_PAGE_PROTECTION | \ + EFI_ACPI_4KB_PAGE_PROTECTION | \ + EFI_ACPI_64KB_PAGE_PROTECTION) + +/** This macro expands to a function that retrieves the + HPET device information from the Configuration Manager. +*/ +GET_OBJECT_LIST ( + EObjNameSpaceX64, + EX64ObjHpetInfo, + CM_X64_HPET_INFO + ); + +/** The ACPI HPET Table. +*/ +STATIC +EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER AcpiHpet = { + ACPI_HEADER ( + EFI_ACPI_6_5_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE, + EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER, + EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_REVISION + ), + // EventTimerBlockId, + 0, + // BaseAddressLower32Bit + { EFI_ACPI_6_5_SYSTEM_MEMORY, 64,0, EFI_ACPI_RESERVED_BYTE, 0 }, + // HpetNumber + 0, + // MainCounterMinimumClockTickInPeriodicMode + 0, + // PageProtectionAndOemAttribute + EFI_ACPI_NO_PAGE_PROTECTION +}; + +/** Update HPET table information. + + @param [in] CfgMgrProtocol Pointer to the Configuration Manager + Protocol Interface. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_NOT_FOUND The required object was not found or + the HPET is not enabled. + @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration + Manager is less than the Object size for the + requested object. + @retval EFI_UNSUPPORTED If invalid protection and oem flags provided. +**/ +STATIC +EFI_STATUS +EFIAPI +HpetUpdateTableInfo ( + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol + ) +{ + CM_X64_HPET_INFO *HpetInfo; + EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_BLOCK_ID HpetBlockId; + EFI_STATUS Status; + + ASSERT (CfgMgrProtocol != NULL); + + // Get the HPET information from the Platform Configuration Manager + Status = GetEX64ObjHpetInfo ( + CfgMgrProtocol, + CM_NULL_TOKEN, + &HpetInfo, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: HPET: Failed to get HPET information." \ + " Status = %r\n", + Status + )); + return Status; + } + + DEBUG (( + DEBUG_INFO, + "HPET: Device base address = 0x%x\n" + " : Minimum clock tick in periodic mode = 0x%x\n" + " : Page protection and Oem flags = 0x%x\n", + HpetInfo->BaseAddressLower32Bit, + HpetInfo->MainCounterMinimumClockTickInPeriodicMode, + HpetInfo->PageProtectionAndOemAttribute + )); + + // Validate the page protection flags bit0 to bit3 + if (((HpetInfo->PageProtectionAndOemAttribute & 0xF) & ~HPET_VALID_PAGE_PROTECTION) != 0) { + DEBUG (( + DEBUG_ERROR, + "ERROR: HPET: unsupported page protection flags = 0x%x\n", + HpetInfo->PageProtectionAndOemAttribute + )); + ASSERT_EFI_ERROR (EFI_UNSUPPORTED); + return EFI_UNSUPPORTED; + } + + // Get HPET Capabilities ID register value and test if HPET is enabled + HpetBlockId.Uint32 = MmioRead32 (HpetInfo->BaseAddressLower32Bit); + + // If mmio address is not mapped + if ((HpetBlockId.Uint32 == MAX_UINT32) || (HpetBlockId.Uint32 == 0)) { + DEBUG ((DEBUG_ERROR, "HPET Capabilities register read failed.\n")); + ASSERT_EFI_ERROR (EFI_NOT_FOUND); + return EFI_NOT_FOUND; + } + + // Validate Reserved and Revision ID + if (HpetBlockId.Bits.Reserved != 0) { + DEBUG ((DEBUG_ERROR, "HPET Reserved bit is set.\n")); + ASSERT_EFI_ERROR (EFI_UNSUPPORTED); + return EFI_UNSUPPORTED; + } + + if (HpetBlockId.Bits.Revision == 0) { + DEBUG ((DEBUG_ERROR, "HPET Revision is not set.\n")); + ASSERT_EFI_ERROR (EFI_UNSUPPORTED); + return EFI_UNSUPPORTED; + } + + // Fill the Event Timer Block ID + AcpiHpet.EventTimerBlockId = HpetBlockId.Uint32; + + // Fill the Base Address + AcpiHpet.BaseAddressLower32Bit.Address = HpetInfo->BaseAddressLower32Bit; + + // Minimum clock tick in periodic mode + AcpiHpet.MainCounterMinimumClockTickInPeriodicMode = HpetInfo->MainCounterMinimumClockTickInPeriodicMode; + + // Page protection and OEM attribute + AcpiHpet.PageProtectionAndOemAttribute = HpetInfo->PageProtectionAndOemAttribute; + + return Status; +} + +/** Construct the HPET table. + + This function invokes the Configuration Manager protocol interface + to get the required 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. +**/ +STATIC +EFI_STATUS +EFIAPI +BuildHpetTable ( + 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; + + 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: HPET: 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 = AddAcpiHeader ( + CfgMgrProtocol, + This, + (EFI_ACPI_DESCRIPTION_HEADER *)&AcpiHpet, + AcpiTableInfo, + sizeof (EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER) + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: HPET: Failed to add ACPI header. Status = %r\n", + Status + )); + goto error_handler; + } + + // Update HPET table info + Status = HpetUpdateTableInfo (CfgMgrProtocol); + if (EFI_ERROR (Status)) { + goto error_handler; + } + + *Table = (EFI_ACPI_DESCRIPTION_HEADER *)&AcpiHpet; +error_handler: + return Status; +} + +/** This macro defines the HPET Table Generator revision. +*/ +#define HPET_GENERATOR_REVISION CREATE_REVISION (1, 0) + +/** The interface for the HPET Table Generator. +*/ +STATIC +CONST +ACPI_TABLE_GENERATOR HpetGenerator = { + // Generator ID + CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdHpet), + // Generator Description + L"ACPI.STD.HPET.GENERATOR", + // ACPI Table Signature + EFI_ACPI_6_5_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE, + // ACPI Table Revision supported by this Generator + EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_REVISION, + // Minimum supported ACPI Table Revision + EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_REVISION, + // Creator ID + TABLE_GENERATOR_CREATOR_ID, + // Creator Revision + HPET_GENERATOR_REVISION, + // Build Table function + BuildHpetTable, + // No additional resources are allocated by the generator. + // Hence the Free Resource function is not required. + NULL, + // 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 +AcpiHpetLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = RegisterAcpiTableGenerator (&HpetGenerator); + DEBUG ((DEBUG_INFO, "HPET: 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 +AcpiHpetLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = DeregisterAcpiTableGenerator (&HpetGenerator); + DEBUG ((DEBUG_INFO, "HPET: Deregister Generator. Status = %r\n", Status)); + ASSERT_EFI_ERROR (Status); + return Status; +} diff --git a/DynamicTablesPkg/Library/Acpi/X64/AcpiHpetLib/AcpiHpetLib.inf b/DynamicTablesPkg/Library/Acpi/X64/AcpiHpetLib/AcpiHpetLib.inf new file mode 100644 index 000000000000..3afc1044de8f --- /dev/null +++ b/DynamicTablesPkg/Library/Acpi/X64/AcpiHpetLib/AcpiHpetLib.inf @@ -0,0 +1,31 @@ +## @file +# Creates ACPI HPET tables for AMD platforms. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 1.30 + BASE_NAME = AcpiHpetLib + FILE_GUID = 858FA64F-8C39-4D4F-A5F1-5DCD61CB79D4 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|DXE_DRIVER + CONSTRUCTOR = AcpiHpetLibConstructor + DESTRUCTOR = AcpiHpetLibDestructor + +[Sources] + AcpiHpetLib.c + +[Packages] + DynamicTablesPkg/DynamicTablesPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + IoLib diff --git a/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c b/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c index c9737f67c379..0f74f3d6b9a4 100644 --- a/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c +++ b/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c @@ -856,6 +856,14 @@ STATIC CONST CM_OBJ_PARSER CmX64ObjWsmtFlagsInfoParser[] = { { "WsmtFlags", 4, "0x%x", NULL } }; +/** A parser for EX64ObjHpetInfo. +*/ +STATIC CONST CM_OBJ_PARSER CmX64ObjHpetInfoParser[] = { + { "BaseAddressLower32Bit", 4, "0x%x", NULL }, + { "MainCounterMinimumClockTickInPeriodicMode", 2, "0x%x", NULL }, + { "PageProtectionAndOemAttribute", 1, "0x%x", NULL } +}; + /** A parser for X64 namespace objects. */ STATIC CONST CM_OBJ_PARSER_ARRAY X64NamespaceObjectParser[] = { @@ -870,6 +878,7 @@ STATIC CONST CM_OBJ_PARSER_ARRAY X64NamespaceObjectParser[] = { CM_PARSER_ADD_OBJECT (EX64ObjFadtResetBlockInfo,CmX64ObjFadtResetBlockInfoParser), CM_PARSER_ADD_OBJECT (EX64ObjFadtMiscInfo, CmX64ObjFadtMiscInfoParser), CM_PARSER_ADD_OBJECT (EX64ObjWsmtFlagsInfo, CmX64ObjWsmtFlagsInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjHpetInfo, CmX64ObjHpetInfoParser), CM_PARSER_ADD_OBJECT_RESERVED (EX64ObjMax) }; diff --git a/DynamicTablesPkg/Readme.md b/DynamicTablesPkg/Readme.md index 84d7ca9fafd6..7a3d499af8ff 100644 --- a/DynamicTablesPkg/Readme.md +++ b/DynamicTablesPkg/Readme.md @@ -515,4 +515,5 @@ The CM_OBJECT_ID type is used to identify the Configuration Manager | 8 | Reset Block Info | | | 9 | Miscellaneous Block Info | | | 10 | Windows protection flag Info | | +| 11 | HPET device Info | | | `*` | All other values are reserved. | |