summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--DynamicTablesPkg/DynamicTables.dsc.inc2
-rw-r--r--DynamicTablesPkg/DynamicTablesPkg.ci.yaml3
-rwxr-xr-xDynamicTablesPkg/Include/AcpiTableGenerator.h1
-rw-r--r--DynamicTablesPkg/Library/Acpi/Common/AcpiHmatLib/AcpiHmatLib.inf29
-rw-r--r--DynamicTablesPkg/Library/Acpi/Common/AcpiHmatLib/HmatGenerator.c751
5 files changed, 785 insertions, 1 deletions
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.<BR>
+#
+# 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.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/AcpiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/AcpiTable.h>
+#include <Library/BaseMemoryLib.h>
+
+// Module specific include files.
+#include <AcpiTableGenerator.h>
+#include <ConfigurationManagerHelper.h>
+#include <ConfigurationManagerObject.h>
+#include <Library/CmObjHelperLib.h>
+#include <Library/TableHelperLib.h>
+#include <Protocol/ConfigurationManagerProtocol.h>
+
+/** 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;
+}