From 9782df45fe5eed9ee5d36319917e86f6a88f0ce8 Mon Sep 17 00:00:00 2001 From: Oleksandr Tymoshenko Date: Mon, 18 May 2026 23:25:37 +0000 Subject: DynamicTablesPkg: Add HMAT generator - Generate HMAT table from ConfigurationManager objects. Co-authored-by: Ryan Heise Co-authored-by: Sophia Wang Signed-off-by: Oleksandr Tymoshenko --- DynamicTablesPkg/DynamicTables.dsc.inc | 2 + DynamicTablesPkg/DynamicTablesPkg.ci.yaml | 3 +- DynamicTablesPkg/Include/AcpiTableGenerator.h | 1 + .../Acpi/Common/AcpiHmatLib/AcpiHmatLib.inf | 29 + .../Acpi/Common/AcpiHmatLib/HmatGenerator.c | 751 +++++++++++++++++++++ 5 files changed, 785 insertions(+), 1 deletion(-) create mode 100644 DynamicTablesPkg/Library/Acpi/Common/AcpiHmatLib/AcpiHmatLib.inf create mode 100644 DynamicTablesPkg/Library/Acpi/Common/AcpiHmatLib/HmatGenerator.c diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc index 47f056bbf0..f9b0fb2dfc 100644 --- a/DynamicTablesPkg/DynamicTables.dsc.inc +++ b/DynamicTablesPkg/DynamicTables.dsc.inc @@ -38,6 +38,7 @@ DynamicTablesPkg/Library/Acpi/Common/AcpiCedtLib/AcpiCedtLib.inf DynamicTablesPkg/Library/Acpi/Common/AcpiDbg2Lib/AcpiDbg2Lib.inf DynamicTablesPkg/Library/Acpi/Common/AcpiFadtLib/AcpiFadtLib.inf + DynamicTablesPkg/Library/Acpi/Common/AcpiHmatLib/AcpiHmatLib.inf DynamicTablesPkg/Library/Acpi/Common/AcpiMcfgLib/AcpiMcfgLib.inf DynamicTablesPkg/Library/Acpi/Common/AcpiPcctLib/AcpiPcctLib.inf DynamicTablesPkg/Library/Acpi/Common/AcpiPpttLib/AcpiPpttLib.inf @@ -137,6 +138,7 @@ NULL|DynamicTablesPkg/Library/Acpi/Common/AcpiCedtLib/AcpiCedtLib.inf NULL|DynamicTablesPkg/Library/Acpi/Common/AcpiDbg2Lib/AcpiDbg2Lib.inf NULL|DynamicTablesPkg/Library/Acpi/Common/AcpiFadtLib/AcpiFadtLib.inf + NULL|DynamicTablesPkg/Library/Acpi/Common/AcpiHmatLib/AcpiHmatLib.inf NULL|DynamicTablesPkg/Library/Acpi/Common/AcpiMcfgLib/AcpiMcfgLib.inf NULL|DynamicTablesPkg/Library/Acpi/Common/AcpiPcctLib/AcpiPcctLib.inf NULL|DynamicTablesPkg/Library/Acpi/Common/AcpiPpttLib/AcpiPpttLib.inf diff --git a/DynamicTablesPkg/DynamicTablesPkg.ci.yaml b/DynamicTablesPkg/DynamicTablesPkg.ci.yaml index f553de7b2c..224051cb03 100644 --- a/DynamicTablesPkg/DynamicTablesPkg.ci.yaml +++ b/DynamicTablesPkg/DynamicTablesPkg.ci.yaml @@ -154,7 +154,8 @@ "rintc", "smcbios", "jedec", - "jep" + "jep", + "sslbi" ], # words to extend to the dictionary for this package "IgnoreStandardPaths": [], # Standard Plugin defined paths that # should be ignore diff --git a/DynamicTablesPkg/Include/AcpiTableGenerator.h b/DynamicTablesPkg/Include/AcpiTableGenerator.h index b706e5ca31..0f827d2cac 100755 --- a/DynamicTablesPkg/Include/AcpiTableGenerator.h +++ b/DynamicTablesPkg/Include/AcpiTableGenerator.h @@ -132,6 +132,7 @@ typedef enum StdAcpiTableId { EStdAcpiTableIdSsdtDmc620Pmu, ///< SSDT DMC620 PMU Generator EStdAcpiTableIdHest, ///< Hest Generator EStdAcpiTableIdEinj, ///< EINJ Generator + EStdAcpiTableIdHmat, ///< HMAT Generator EStdAcpiTableIdMax } ESTD_ACPI_TABLE_ID; diff --git a/DynamicTablesPkg/Library/Acpi/Common/AcpiHmatLib/AcpiHmatLib.inf b/DynamicTablesPkg/Library/Acpi/Common/AcpiHmatLib/AcpiHmatLib.inf new file mode 100644 index 0000000000..754802bc0c --- /dev/null +++ b/DynamicTablesPkg/Library/Acpi/Common/AcpiHmatLib/AcpiHmatLib.inf @@ -0,0 +1,29 @@ +## @file +# HMAT Table Generator +# +# Copyright (c) 2026, Google LLC. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = AcpiHmatLib + FILE_GUID = 1724d37a-fb05-4fe6-bb13-c04a46efe0ac + VERSION_STRING = 1.0 + MODULE_TYPE = DXE_DRIVER + LIBRARY_CLASS = NULL|DXE_DRIVER + CONSTRUCTOR = AcpiHmatLibConstructor + DESTRUCTOR = AcpiHmatLibDestructor + +[Sources] + HmatGenerator.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + DynamicTablesPkg/DynamicTablesPkg.dec + +[LibraryClasses] + BaseLib + CmObjHelperLib diff --git a/DynamicTablesPkg/Library/Acpi/Common/AcpiHmatLib/HmatGenerator.c b/DynamicTablesPkg/Library/Acpi/Common/AcpiHmatLib/HmatGenerator.c new file mode 100644 index 0000000000..fe980f1cdc --- /dev/null +++ b/DynamicTablesPkg/Library/Acpi/Common/AcpiHmatLib/HmatGenerator.c @@ -0,0 +1,751 @@ +/** @file + HMAT Table Generator + + Copyright (c) 2026, Google LLC. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + +// Module specific include files. +#include +#include +#include +#include +#include +#include + +/** Standard HMAT Generator + +Requirements: + The following Configuration Manager Object(s) are required by + this Generator: + - EArchCommonObjMemoryLatBwInfo + - EArchCommonObjMemoryProximityDomainAttrInfo + - EArchCommonObjProximityDomainInfo + - EArchCommonObjProximityDomainRelationInfo + +*/ + +/** Retrieve the Proximity Domain Info */ +GET_OBJECT_LIST ( + EObjNameSpaceArchCommon, + EArchCommonObjProximityDomainInfo, + CM_ARCH_COMMON_PROXIMITY_DOMAIN_INFO + ); + +/** Retrieve the Proximity Domain Relation Info. */ +GET_OBJECT_LIST ( + EObjNameSpaceArchCommon, + EArchCommonObjProximityDomainRelationInfo, + CM_ARCH_COMMON_PROXIMITY_DOMAIN_RELATION_INFO + ); + +/** Retrieve the Proximity Domain Attr Info */ +GET_OBJECT_LIST ( + EObjNameSpaceArchCommon, + EArchCommonObjMemoryProximityDomainAttrInfo, + CM_ARCH_COMMON_MEMORY_PROXIMITY_DOMAIN_ATTR_INFO + ); + +/** Retrieve the SSLBI Info */ +GET_OBJECT_LIST ( + EObjNameSpaceArchCommon, + EArchCommonObjMemoryLatBwInfo, + CM_ARCH_COMMON_MEMORY_LAT_BW_INFO + ); + +/** Find an index of the specified domain ID in an array. + + @param [in] DomainId Domain ID to find. + @param [in] DomainIds Pointer to an array with domain IDs. + @param [in] DomainIdCount Number of elements in DomainIds array. + @param [out] DomainIdIndex Pointer where the index of the found ID is stored. + Can be NULL if the actual index doesn't matter. + + @retval EFI_SUCCESS If DomainId was found + @retval EFI_NOT_FOUND If DomainId wasn't found +**/ +STATIC +EFI_STATUS +FindDomainIndex ( + IN UINT32 DomainId, + IN UINT32 *DomainIds, + IN UINTN DomainIdCount, + OUT UINTN *DomainIdIndex OPTIONAL + ) +{ + UINTN Index; + + for (Index = 0; Index < DomainIdCount; Index++) { + if (DomainIds[Index] == DomainId) { + if (DomainIdIndex != NULL) { + *DomainIdIndex = Index; + } + + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** Computes how many bytes are required to hold an ACPI HMAT SSLBI table. + + @param [in] InitiatorProximityDomainCount Number of initiator domains in an SSLBI record. + @param [in] TargetProximityDomainCount Number of target domains in an SSLBI record. + + @retval Bytes required to store SSLBI record. +**/ +STATIC +UINT32 +GetSslbiTableSize ( + IN UINT32 InitiatorProximityDomainCount, + IN UINT32 TargetProximityDomainCount + ) +{ + return sizeof (UINT32) * InitiatorProximityDomainCount + + sizeof (UINT32) * TargetProximityDomainCount + + sizeof (UINT16) * InitiatorProximityDomainCount * TargetProximityDomainCount + + sizeof (EFI_ACPI_6_4_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO); +} + +/** Populate SSLBI record and return the actual size of the record to caller. + + @param [in] CfgMgrProtocol ConfigurationManager protocol. + @param [in] CmMemLatBwInfo SSLBI record information. + @param [in] CmMemLatBwRelations Array of relations to be populated into SSLBI. + @param [in] CmMemLatBwRelationCount Number of elements in the relations array. + @param [in] ProximityDomainCount Maximum number of proximity domains, used to + sanity check the relations array data. + @param [in, out] MemLatBwInfo SSLBI to be populated. Caller is responsible for + allocating memory area large enough to fit the data. + @param [out] RecordLength Actual size of the SSLBI record in bytes, + header + relations matrix. + + @retval EFI_INVALID_PARAMETER The relations matrix data is not valid: it's either spare + or number of initiators/targets larger than number of domains + in the system. +**/ +STATIC +EFI_STATUS +AddMemLatBwInfo ( + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol, + IN CONST CM_ARCH_COMMON_MEMORY_LAT_BW_INFO *CmMemLatBwInfo, + IN CONST CM_ARCH_COMMON_PROXIMITY_DOMAIN_RELATION_INFO *CmMemLatBwRelations, + IN UINTN CmMemLatBwRelationCount, + IN UINT32 ProximityDomainCount, + IN OUT EFI_ACPI_6_4_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO *MemLatBwInfo, + OUT UINTN *RecordLength + ) +{ + UINTN Index; + UINT32 *InitiatorDomains; + UINT32 InitiatorDomainCount; + UINT32 *TargetDomains; + UINT32 TargetDomainCount; + EFI_STATUS Status; + UINT32 DomainId; + UINTN InitiatorIdx; + UINTN TargetIdx; + UINT16 *Relations; + UINT8 *TablePtr; + + ASSERT (CfgMgrProtocol != NULL); + ASSERT (MemLatBwInfo != NULL); + ASSERT (CmMemLatBwInfo != NULL); + ASSERT (CmMemLatBwRelations != NULL); + ASSERT (CmMemLatBwRelationCount > 0); + ASSERT (ProximityDomainCount > 0); + ASSERT (RecordLength != NULL); + + if (CmMemLatBwRelationCount == 0) { + return EFI_INVALID_PARAMETER; + } + + MemLatBwInfo->Type = EFI_ACPI_6_4_HMAT_TYPE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO; + + CopyMem (&MemLatBwInfo->Flags, &CmMemLatBwInfo->Flags, sizeof (UINT8)); + if ((MemLatBwInfo->Flags.MemoryHierarchy > EFI_ACPI_6_4_HMAT_MEMORY_HIERARCHY_L3_CACHE) || + (MemLatBwInfo->Flags.Reserved != 0)) + { + return EFI_INVALID_PARAMETER; + } + + MemLatBwInfo->DataType = CmMemLatBwInfo->DataType; + MemLatBwInfo->MinTransferSize = CmMemLatBwInfo->MinTransferSize; + MemLatBwInfo->EntryBaseUnit = CmMemLatBwInfo->EntryBaseUnit; + + TablePtr = (UINT8 *)MemLatBwInfo; + + TablePtr += sizeof (EFI_ACPI_6_4_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO); + InitiatorDomainCount = 0; + InitiatorDomains = (UINT32 *)TablePtr; + + // Append Initiator ProximityDomains. + for (Index = 0; Index < CmMemLatBwRelationCount; Index++) { + Status = GetProximityDomainId ( + CfgMgrProtocol, + 0, + CmMemLatBwRelations[Index].FirstDomainToken, + &DomainId + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + if (FindDomainIndex (DomainId, InitiatorDomains, InitiatorDomainCount, NULL) == EFI_NOT_FOUND) { + if (InitiatorDomainCount >= ProximityDomainCount) { + return EFI_INVALID_PARAMETER; + } + + InitiatorDomains[InitiatorDomainCount] = DomainId; + InitiatorDomainCount++; + } + } + + // Append Target ProximityDomains. + TargetDomainCount = 0; + TargetDomains = InitiatorDomains + InitiatorDomainCount; + for (Index = 0; Index < CmMemLatBwRelationCount; Index++) { + Status = GetProximityDomainId ( + CfgMgrProtocol, + 0, + CmMemLatBwRelations[Index].SecondDomainToken, + &DomainId + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + if (FindDomainIndex (DomainId, TargetDomains, TargetDomainCount, NULL) == EFI_NOT_FOUND) { + if (TargetDomainCount >= ProximityDomainCount) { + return EFI_INVALID_PARAMETER; + } + + TargetDomains[TargetDomainCount] = DomainId; + TargetDomainCount++; + } + } + + DEBUG (( + DEBUG_INFO, + "HMAT: Lat/Bw info table dimensions: %d x %d\n", + InitiatorDomainCount, + TargetDomainCount + )); + + if (InitiatorDomainCount * TargetDomainCount != CmMemLatBwRelationCount) { + DEBUG (( + DEBUG_ERROR, + "HMAT: Lat/Bw info table dimensions %dx%d do not match elements count %d (should be %d)\n", + InitiatorDomainCount, + TargetDomainCount, + CmMemLatBwRelationCount, + InitiatorDomainCount * TargetDomainCount + )); + return EFI_INVALID_PARAMETER; + } + + Relations = (UINT16 *)(TargetDomains + TargetDomainCount); + for (Index = 0; Index < CmMemLatBwRelationCount; Index++) { + Status = GetProximityDomainId ( + CfgMgrProtocol, + 0, + CmMemLatBwRelations[Index].FirstDomainToken, + &DomainId + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = FindDomainIndex (DomainId, InitiatorDomains, InitiatorDomainCount, &InitiatorIdx); + ASSERT_EFI_ERROR (Status); + + Status = GetProximityDomainId ( + CfgMgrProtocol, + 0, + CmMemLatBwRelations[Index].SecondDomainToken, + &DomainId + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = FindDomainIndex (DomainId, TargetDomains, TargetDomainCount, &TargetIdx); + ASSERT_EFI_ERROR (Status); + + if (CmMemLatBwRelations[Index].Relation > MAX_UINT16) { + DEBUG (( + DEBUG_ERROR, + "HMAT: relation value of element %d does not fit in 16 bits: %d\n", + Index, + CmMemLatBwRelations[Index].Relation + )); + return EFI_INVALID_PARAMETER; + } + + Relations[InitiatorIdx * TargetDomainCount + TargetIdx] = CmMemLatBwRelations[Index].Relation & 0xFFFF; + } + + // Update record info + MemLatBwInfo->Length = GetSslbiTableSize (InitiatorDomainCount, TargetDomainCount); + MemLatBwInfo->NumberOfInitiatorProximityDomains = InitiatorDomainCount; + MemLatBwInfo->NumberOfTargetProximityDomains = TargetDomainCount; + *RecordLength = MemLatBwInfo->Length; + + return EFI_SUCCESS; +} + +/** Add the MemProxDomainAttr Information record to the HMAT Table. + + @param [in] CfgMgrProtocol Pointer to the Configuration Manager Protocol Interface. + @param [in] MemProximityDomainAttrInfo Pointer to a Proximity Domain Attribute array in an HMAT table. + The caller is responsible for allocating enough memory to fit + the data. + @param [in] CmMemProximityDomainAttrInfo Pointer ConfigurationManager objects array with Domain Attribute data. + @param [in] MemProximityDomainAttrCount Number of entries in CmMemProximityDomainAttrInfo. + + @retval EFI_SUCCESS if attributes were added + @retval error code otherwise +**/ +STATIC +EFI_STATUS +AddMemProximityDomainAttrInfo ( + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol, + IN EFI_ACPI_6_4_HMAT_STRUCTURE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES *MemProximityDomainAttrInfo, + IN CONST CM_ARCH_COMMON_MEMORY_PROXIMITY_DOMAIN_ATTR_INFO *CmMemProximityDomainAttrInfo, + IN UINT32 MemProximityDomainAttrCount + ) +{ + EFI_STATUS Status; + + if (MemProximityDomainAttrCount == 0) { + return EFI_SUCCESS; + } + + ASSERT (MemProximityDomainAttrInfo != NULL); + ASSERT (CmMemProximityDomainAttrInfo != NULL); + + while (MemProximityDomainAttrCount-- != 0) { + MemProximityDomainAttrInfo->Type = EFI_ACPI_6_4_HMAT_TYPE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES; + MemProximityDomainAttrInfo->Length = sizeof (EFI_ACPI_6_4_HMAT_STRUCTURE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES); + CopyMem (&MemProximityDomainAttrInfo->Flags, &CmMemProximityDomainAttrInfo->Flags, sizeof (UINT16)); + if (MemProximityDomainAttrInfo->Flags.Reserved != 0) { + return EFI_INVALID_PARAMETER; + } + + if (CmMemProximityDomainAttrInfo->InitiatorProximityDomain + == CmMemProximityDomainAttrInfo->MemoryProximityDomain) + { + return EFI_INVALID_PARAMETER; + } + + Status = GetProximityDomainId ( + CfgMgrProtocol, + 0, + CmMemProximityDomainAttrInfo->InitiatorProximityDomain, + &MemProximityDomainAttrInfo->InitiatorProximityDomain + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = GetProximityDomainId ( + CfgMgrProtocol, + 0, + CmMemProximityDomainAttrInfo->MemoryProximityDomain, + &MemProximityDomainAttrInfo->MemoryProximityDomain + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + MemProximityDomainAttrInfo++; + CmMemProximityDomainAttrInfo++; + } + + return EFI_SUCCESS; +} + +/** Free any resources allocated for constructing the table. + + @param [in] This Pointer to the ACPI 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 ACPI Table. + + @retval EFI_SUCCESS The resources were freed successfully. + @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid. +**/ +STATIC +EFI_STATUS +EFIAPI +FreeHmatTable ( + 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: HMAT: Invalid Table Pointer\n")); + ASSERT ((Table != NULL) && (*Table != NULL)); + return EFI_INVALID_PARAMETER; + } + + if (*Table != NULL) { + FreePool (*Table); + *Table = NULL; + } + + return EFI_SUCCESS; +} + +/** Construct the HMAT ACPI table. + + 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 FreeXXXXTableResourcesEx function. + + @param [in] This Pointer to the ACPI table generator. + @param [in] AcpiTableInfo Pointer to the ACPI table information. + @param [in] CfgMgrProtocol Pointer to the Configuration Manager + Protocol interface. + @param [out] Table Pointer to the generated ACPI table. + + @retval EFI_SUCCESS Table generated successfully. + @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration + Manager is less than the Object size for + the requested object. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_NOT_FOUND Could not find information. + @retval EFI_OUT_OF_RESOURCES Could not allocate memory. +**/ +STATIC +EFI_STATUS +EFIAPI +BuildHmatTable ( + IN CONST ACPI_TABLE_GENERATOR *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; + UINTN TableSize; + UINT32 MemProximityDomainAttrCount; + UINT32 MemLatBwCount; + CM_ARCH_COMMON_MEMORY_PROXIMITY_DOMAIN_ATTR_INFO *MemProximityDomainAttrInfo; + CM_ARCH_COMMON_MEMORY_LAT_BW_INFO *MemLatBwInfos; + CM_ARCH_COMMON_PROXIMITY_DOMAIN_RELATION_INFO *MemLatBwRelations; + CM_ARCH_COMMON_PROXIMITY_DOMAIN_INFO *ProximityDomainInfo; + UINT32 ProximityDomainInfoCount; + UINT32 MemLatBwRelationsCount; + UINTN MemProximityDomainAttrOffset; + UINTN MemLatBwOffset; + UINT32 Index; + UINT64 MaxLatBwSize; + UINTN LatBwEntrySize; + EFI_ACPI_6_4_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_HEADER *Hmat; + VOID *FinalTable; + + 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: HMAT: 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 = GetEArchCommonObjProximityDomainInfo ( + CfgMgrProtocol, + CM_NULL_TOKEN, + &ProximityDomainInfo, + &ProximityDomainInfoCount + ); + + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: HMAT: Failed to get ProximityDomainInfo. Status = %r\n", + Status + )); + goto error_handler; + } + + MemProximityDomainAttrCount = 0; + + Status = GetEArchCommonObjMemoryProximityDomainAttrInfo ( + CfgMgrProtocol, + CM_NULL_TOKEN, + &MemProximityDomainAttrInfo, + &MemProximityDomainAttrCount + ); + + if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: HMAT: Failed to get MemProximityDomain Info. Status = %r\n", + Status + )); + goto error_handler; + } + + MemLatBwCount = 0; + + Status = GetEArchCommonObjMemoryLatBwInfo ( + CfgMgrProtocol, + CM_NULL_TOKEN, + &MemLatBwInfos, + &MemLatBwCount + ); + + if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: HMAT: Failed to get MemLatBwInfo. Status = %r\n", + Status + )); + goto error_handler; + } + + TableSize = sizeof (EFI_ACPI_6_4_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_HEADER); + + MemProximityDomainAttrOffset = TableSize; + TableSize += + (sizeof (EFI_ACPI_6_4_HMAT_STRUCTURE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES) * MemProximityDomainAttrCount); + + MemLatBwOffset = TableSize; + + // The largest SSLBI entry is full matrix where all proximity + // domains act as initiators and targets. Go for max case, adjust size later. + MaxLatBwSize = GetSslbiTableSize (ProximityDomainInfoCount, ProximityDomainInfoCount); + TableSize += MemLatBwCount * MaxLatBwSize; + + if (TableSize > MAX_UINT32) { + return EFI_INVALID_PARAMETER; + } + + // Allocate the Buffer for HMAT table + *Table = (EFI_ACPI_DESCRIPTION_HEADER *)AllocateZeroPool (TableSize); + + if (*Table == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG (( + DEBUG_ERROR, + "ERROR: HMAT: Failed to allocate memory for HMAT Table, Size = %d," \ + " Status = %r\n", + TableSize, + Status + )); + goto error_handler; + } + + Hmat = (EFI_ACPI_6_4_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_HEADER *)*Table; + + // Build HMAT table. + Status = AddAcpiHeader ( + CfgMgrProtocol, + This, + &Hmat->Header, + AcpiTableInfo, + (UINT32)TableSize + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: HMAT: Failed to add ACPI header. Status = %r\n", + Status + )); + goto error_handler; + } + + Status = AddMemProximityDomainAttrInfo ( + CfgMgrProtocol, + (EFI_ACPI_6_4_HMAT_STRUCTURE_MEMORY_PROXIMITY_DOMAIN_ATTRIBUTES *)((UINT8 *)Hmat + MemProximityDomainAttrOffset), + MemProximityDomainAttrInfo, + MemProximityDomainAttrCount + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to add Proximity Domain Attr structures: %r\n", __func__, Status)); + goto error_handler; + } + + for (Index = 0; Index < MemLatBwCount; Index++) { + Status = GetEArchCommonObjProximityDomainRelationInfo ( + CfgMgrProtocol, + MemLatBwInfos[Index].RelativeDistanceArray, + &MemLatBwRelations, + &MemLatBwRelationsCount + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to get relative distances array: %r\n", __func__, Status)); + goto error_handler; + } + + Status = AddMemLatBwInfo ( + CfgMgrProtocol, + &MemLatBwInfos[Index], + MemLatBwRelations, + MemLatBwRelationsCount, + ProximityDomainInfoCount, + (EFI_ACPI_6_4_HMAT_STRUCTURE_SYSTEM_LOCALITY_LATENCY_AND_BANDWIDTH_INFO *)((UINT8 *)Hmat + MemLatBwOffset), + &LatBwEntrySize + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to add Lat/Bw info: %r\n", __func__, Status)); + goto error_handler; + } + + MemLatBwOffset += LatBwEntrySize; + } + + // Update header with the actual length of the generated table + // and re-allocate it to an actual size + Hmat->Header.Length = (UINT32)MemLatBwOffset; + FinalTable = AllocateCopyPool (Hmat->Header.Length, *Table); + if (FinalTable == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG (( + DEBUG_ERROR, + "ERROR: HMAT: Failed to allocate memory for HMAT Table, Size = %d," \ + " Status = %r\n", + Hmat->Header.Length, + Status + )); + goto error_handler; + } + + FreePool (*Table); + *Table = FinalTable; + + return Status; + +error_handler: + if (*Table != NULL) { + FreePool (*Table); + *Table = NULL; + } + + return Status; +} + +/** This macro defines the HMAT Table Generator revision. +*/ +#define HMAT_GENERATOR_REVISION CREATE_REVISION (1, 0) + +/** The interface for the HMAT Table Generator. +*/ +STATIC +CONST +ACPI_TABLE_GENERATOR HmatGenerator = { + // Generator ID + CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdHmat), + // Generator Description + L"ACPI.STD.HMAT.GENERATOR", + // ACPI Table Signature + EFI_ACPI_6_4_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_SIGNATURE, + // ACPI Table Revision supported by this Generator + EFI_ACPI_6_4_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_REVISION, + // Minimum supported ACPI Table Revision + EFI_ACPI_6_4_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_REVISION, + // Creator ID + TABLE_GENERATOR_CREATOR_ID_ARM, + // Creator Revision + HMAT_GENERATOR_REVISION, + // Build table function. Use the extended version instead. + BuildHmatTable, + // Free table function. Use the extended version instead. + FreeHmatTable, + // Extended Build table function. + NULL, + // Extended free function. + 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 +AcpiHmatLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = RegisterAcpiTableGenerator (&HmatGenerator); + DEBUG ((DEBUG_INFO, "HMAT: 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 +AcpiHmatLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = DeregisterAcpiTableGenerator (&HmatGenerator); + DEBUG ((DEBUG_INFO, "HMAT: Deregister Generator. Status = %r\n", Status)); + ASSERT_EFI_ERROR (Status); + return Status; +} -- cgit v1.2.3