blob: fe980f1cdcbdd76109098a9d1083b0ead5ff2b99 [file]
/** @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;
}