summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVarshitPandya <varshit.pandya@arm.com>2026-07-01 17:05:09 +0100
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2026-07-03 10:54:53 +0000
commite54671e9ef14ffc440ca515f75543d227f72f3c8 (patch)
treec70afe811adbfb686fbedac28733e49f9d2e20f3
parent5a64d2c5e1b4c51440e335fe0b2c66065082ccc6 (diff)
downloadedk2-e54671e9ef14ffc440ca515f75543d227f72f3c8.tar.gz
edk2-e54671e9ef14ffc440ca515f75543d227f72f3c8.zip
DynamicTablesPkg: Smbios Memory Device Mapped Address (Type 20)
Add an SMBIOS Type 20 generator for Memory Device Mapped Address structures. The generator builds one Type 20 table per Memory Device Mapped Address CM object, validates the address range, encodes extended addresses when the 32-bit address fields cannot represent the range, and maps optional Type 17 and Type 19 CM object references to SMBIOS handles. If either reference token is CM_NULL_TOKEN, the corresponding SMBIOS handle is set to SMBIOS_HANDLE_INVALID. Signed-off-by: Varshit Pandya <varshit.pandya@arm.com>
-rw-r--r--DynamicTablesPkg/DynamicTables.dsc.inc2
-rw-r--r--DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h29
-rw-r--r--DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c14
-rw-r--r--DynamicTablesPkg/Library/Smbios/SmbiosType20Lib/SmbiosType20Generator.c407
-rw-r--r--DynamicTablesPkg/Library/Smbios/SmbiosType20Lib/SmbiosType20Lib.inf34
5 files changed, 486 insertions, 0 deletions
diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc
index 75bbfc38ca..47f056bbf0 100644
--- a/DynamicTablesPkg/DynamicTables.dsc.inc
+++ b/DynamicTablesPkg/DynamicTables.dsc.inc
@@ -115,6 +115,7 @@
DynamicTablesPkg/Library/Smbios/SmbiosType16Lib/SmbiosType16Lib.inf
DynamicTablesPkg/Library/Smbios/SmbiosType17Lib/SmbiosType17Lib.inf
DynamicTablesPkg/Library/Smbios/SmbiosType19Lib/SmbiosType19Lib.inf
+ DynamicTablesPkg/Library/Smbios/SmbiosType20Lib/SmbiosType20Lib.inf
DynamicTablesPkg/Library/Smbios/SmbiosType23Lib/SmbiosType23Lib.inf
DynamicTablesPkg/Library/Smbios/SmbiosType26Lib/SmbiosType26Lib.inf
DynamicTablesPkg/Library/Smbios/SmbiosType27Lib/SmbiosType27Lib.inf
@@ -170,6 +171,7 @@
NULL|DynamicTablesPkg/Library/Smbios/SmbiosType16Lib/SmbiosType16Lib.inf
NULL|DynamicTablesPkg/Library/Smbios/SmbiosType17Lib/SmbiosType17Lib.inf
NULL|DynamicTablesPkg/Library/Smbios/SmbiosType19Lib/SmbiosType19Lib.inf
+ NULL|DynamicTablesPkg/Library/Smbios/SmbiosType20Lib/SmbiosType20Lib.inf
NULL|DynamicTablesPkg/Library/Smbios/SmbiosType23Lib/SmbiosType23Lib.inf
NULL|DynamicTablesPkg/Library/Smbios/SmbiosType26Lib/SmbiosType26Lib.inf
NULL|DynamicTablesPkg/Library/Smbios/SmbiosType27Lib/SmbiosType27Lib.inf
diff --git a/DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h b/DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h
index ba26118f6c..214e919dc3 100644
--- a/DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h
+++ b/DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h
@@ -88,6 +88,7 @@ typedef enum ArchCommonObjectID {
EArchCommonObjVoltageProbeInfo, ///< 60 - Voltage Probe Info
EArchCommonObjElectricalCurrentProbeInfo, ///< 61 - Electrical Current Probe Info
EArchCommonObjSystemResetInfo, ///< 62 - System Reset Info
+ EArchCommonObjMemoryDeviceMappedAddress, ///< 63 - Memory Device Mapped Address Info
EArchCommonObjMax
} EARCH_COMMON_OBJECT_ID;
@@ -1469,6 +1470,34 @@ typedef struct CmArchCommonMemoryArrayMappedAddress {
UINT8 NumMemDevices;
} CM_ARCH_COMMON_MEMORY_ARRAY_MAPPED_ADDRESS;
+/** A structure that describes a Memory Device Mapped Address.
+
+ SMBIOS Specification v3.9.0 Type 20
+
+ ID: EArchCommonObjMemoryDeviceMappedAddress
+**/
+typedef struct CmArchCommonMemoryDeviceMappedAddress {
+ /// CM Object Token uniquely identifying this mapped address entry.
+ CM_OBJECT_TOKEN MemoryDeviceMappedAddressToken;
+ /// Starting physical address of the mapped memory range.
+ EFI_PHYSICAL_ADDRESS StartingAddress;
+ /// Ending physical address of the mapped memory range.
+ EFI_PHYSICAL_ADDRESS EndingAddress;
+ /// CM Object Token of the associated Memory Device.
+ CM_OBJECT_TOKEN MemoryDeviceInfoToken;
+ /// CM Object Token of the associated Memory Array Mapped Address.
+ CM_OBJECT_TOKEN MemoryArrayMappedAddressToken;
+ /// Identifies the position of the referenced memory device in a row.
+ /// Set to 0xFF if unknown.
+ UINT8 PartitionRowPosition;
+ /// Identifies the position of the referenced memory device in an interleave.
+ /// Set to 0xFF if unknown.
+ UINT8 InterleavePosition;
+ /// Number of consecutive rows from the referenced memory device.
+ /// Set to 0xFF if unknown.
+ UINT8 InterleavedDataDepth;
+} CM_ARCH_COMMON_MEMORY_DEVICE_MAPPED_ADDRESS;
+
/** A structure that describes cooling device.
SMBIOS Specification v3.9.0 Type 27
diff --git a/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c b/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c
index a91c5d70fb..ab4e45c079 100644
--- a/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c
+++ b/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c
@@ -1223,6 +1223,19 @@ STATIC CONST CM_OBJ_PARSER CmArchCommonMemoryArrayMappedAddressParser[] = {
{ "NumMemDevices", sizeof (UINT8), "0x%u", NULL },
};
+/** A parser for EArchCommonObjMemoryDeviceMappedAddress.
+*/
+STATIC CONST CM_OBJ_PARSER CmArchCommonMemoryDeviceMappedAddressParser[] = {
+ { "MemoryDeviceMappedAddressToken", sizeof (CM_OBJECT_TOKEN), "0x%p", NULL },
+ { "StartingAddress", sizeof (EFI_PHYSICAL_ADDRESS), "0x%lx", NULL },
+ { "EndingAddress", sizeof (EFI_PHYSICAL_ADDRESS), "0x%lx", NULL },
+ { "MemoryDeviceInfoToken", sizeof (CM_OBJECT_TOKEN), "0x%p", NULL },
+ { "MemoryArrayMappedAddressToken", sizeof (CM_OBJECT_TOKEN), "0x%p", NULL },
+ { "PartitionRowPosition", sizeof (UINT8), "0x%u", NULL },
+ { "InterleavePosition", sizeof (UINT8), "0x%u", NULL },
+ { "InterleavedDataDepth", sizeof (UINT8), "0x%u", NULL },
+};
+
/** A parser for EArchCommonObjCoolingDeviceInfo.
*/
STATIC CONST CM_OBJ_PARSER CmArchCommonCoolingDeviceInfoParser[] = {
@@ -1358,6 +1371,7 @@ STATIC CONST CM_OBJ_PARSER_ARRAY ArchCommonNamespaceObjectParser[] = {
CM_PARSER_ADD_OBJECT (EArchCommonObjVoltageProbeInfo, CmArchCommonVoltageProbeInfoParser),
CM_PARSER_ADD_OBJECT (EArchCommonObjElectricalCurrentProbeInfo, CmArchCommonElectricalCurrentProbeInfoParser),
CM_PARSER_ADD_OBJECT (EArchCommonObjSystemResetInfo, CmArchCommonSystemResetInfoParser),
+ CM_PARSER_ADD_OBJECT (EArchCommonObjMemoryDeviceMappedAddress, CmArchCommonMemoryDeviceMappedAddressParser),
CM_PARSER_ADD_OBJECT_RESERVED (EArchCommonObjMax)
};
diff --git a/DynamicTablesPkg/Library/Smbios/SmbiosType20Lib/SmbiosType20Generator.c b/DynamicTablesPkg/Library/Smbios/SmbiosType20Lib/SmbiosType20Generator.c
new file mode 100644
index 0000000000..3b7d0e8919
--- /dev/null
+++ b/DynamicTablesPkg/Library/Smbios/SmbiosType20Lib/SmbiosType20Generator.c
@@ -0,0 +1,407 @@
+/** @file
+ SMBIOS Type20 Table Generator.
+
+ Copyright (c) 2026, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SmbiosStringTableLib.h>
+
+// Module specific include files.
+#include <ConfigurationManagerObject.h>
+#include <ConfigurationManagerHelper.h>
+#include <Protocol/ConfigurationManagerProtocol.h>
+#include <Protocol/DynamicTableFactoryProtocol.h>
+#include <IndustryStandard/SmBios.h>
+
+/** SMBIOS Type 20 Memory Device Mapped Address Generator
+
+Requirements:
+ The following Configuration Manager Object(s) are required by
+ this Generator:
+ - EArchCommonObjMemoryDeviceMappedAddress
+
+ The following Configuration Manager Object(s) are required when
+ the corresponding token is not CM_NULL_TOKEN:
+ - EArchCommonObjMemoryDeviceInfo
+ - EArchCommonObjMemoryArrayMappedAddress
+*/
+
+/**
+ This macro expands to a function that retrieves the Memory Device
+ Mapped Address information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArchCommon,
+ EArchCommonObjMemoryDeviceMappedAddress,
+ CM_ARCH_COMMON_MEMORY_DEVICE_MAPPED_ADDRESS
+ );
+
+#define EXTENDED_ADDRESS_THRESHOLD (0xFFFFFFFFULL)
+
+/**
+ Free any resources allocated when installing SMBIOS Type 20 table.
+
+ @param [in] This Pointer to the SMBIOS table generator.
+ @param [in] TableFactoryProtocol Pointer to the SMBIOS Table Factory
+ Protocol interface.
+ @param [in] SmbiosTableInfo Pointer to the SMBIOS table information.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol interface.
+ @param [in] Table Pointer to the SMBIOS table.
+ @param [in] CmObjectToken Pointer to the CM ObjectToken Array.
+ @param [in] TableCount Number of SMBIOS tables.
+
+ @retval EFI_SUCCESS Resources freed successfully.
+**/
+STATIC
+EFI_STATUS
+FreeSmbiosType20TableEx (
+ IN CONST SMBIOS_TABLE_GENERATOR *CONST This,
+ IN CONST EDKII_DYNAMIC_TABLE_FACTORY_PROTOCOL *CONST TableFactoryProtocol,
+ IN CONST CM_STD_OBJ_SMBIOS_TABLE_INFO *CONST SmbiosTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
+ IN SMBIOS_STRUCTURE ***CONST Table,
+ IN CM_OBJECT_TOKEN **CmObjectToken,
+ IN CONST UINTN TableCount
+ )
+{
+ UINTN Index;
+ SMBIOS_STRUCTURE **TableList;
+
+ TableList = *Table;
+ for (Index = 0; Index < TableCount; Index++) {
+ if (TableList[Index] != NULL) {
+ FreePool (TableList[Index]);
+ }
+ }
+
+ if (*CmObjectToken != NULL) {
+ FreePool (*CmObjectToken);
+ }
+
+ if (TableList != NULL) {
+ FreePool (TableList);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** Construct SMBIOS Type 20 Table describing memory device mapped addresses.
+
+ If this function allocates any resources then they must be freed
+ in the FreeSmbiosType20TableEx function.
+
+ @param [in] This Pointer to the SMBIOS table generator.
+ @param [in] TableFactoryProtocol Pointer to the SMBIOS Table Factory
+ Protocol interface.
+ @param [in] SmbiosTableInfo Pointer to the SMBIOS table information.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol interface.
+ @param [out] Table Pointer to the SMBIOS table.
+ @param [out] CmObjectToken Pointer to the CM ObjectToken Array.
+ @param [out] TableCount Number of SMBIOS tables.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Could not find required information.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+BuildSmbiosType20TableEx (
+ IN CONST SMBIOS_TABLE_GENERATOR *This,
+ IN CONST EDKII_DYNAMIC_TABLE_FACTORY_PROTOCOL *CONST TableFactoryProtocol,
+ IN CM_STD_OBJ_SMBIOS_TABLE_INFO *CONST SmbiosTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
+ OUT SMBIOS_STRUCTURE ***Table,
+ OUT CM_OBJECT_TOKEN **CONST CmObjectToken,
+ OUT UINTN *CONST TableCount
+ )
+{
+ EFI_STATUS Status;
+ UINT32 NumMemDeviceMap;
+ CM_ARCH_COMMON_MEMORY_DEVICE_MAPPED_ADDRESS *MemoryDeviceMapInfo;
+ SMBIOS_STRUCTURE **TableList;
+ CM_OBJECT_TOKEN *CmObjectList;
+ SMBIOS_TABLE_TYPE20 *SmbiosRecord;
+ SMBIOS_HANDLE_MAP *HandleMap;
+ UINT64 StartingAddressKb;
+ UINT64 EndingAddressKb;
+ UINTN Index;
+
+ TableList = NULL;
+ CmObjectList = NULL;
+ SmbiosRecord = NULL;
+
+ ASSERT (This != NULL);
+ ASSERT (TableFactoryProtocol != NULL);
+ ASSERT (SmbiosTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (Table != NULL);
+ ASSERT (CmObjectToken != NULL);
+ ASSERT (TableCount != NULL);
+ ASSERT (SmbiosTableInfo->TableGeneratorId == This->GeneratorID);
+
+ if ((This == NULL) || (TableFactoryProtocol == NULL) ||
+ (SmbiosTableInfo == NULL) || (CfgMgrProtocol == NULL) ||
+ (Table == NULL) || (CmObjectToken == NULL) || (TableCount == NULL) ||
+ (SmbiosTableInfo->TableGeneratorId != This->GeneratorID))
+ {
+ DEBUG ((DEBUG_ERROR, "%a: Invalid Parameter\n", __func__));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Table = NULL;
+ *CmObjectToken = NULL;
+ *TableCount = 0;
+
+ Status = GetEArchCommonObjMemoryDeviceMappedAddress (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &MemoryDeviceMapInfo,
+ &NumMemDeviceMap
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Failed to get Memory Device Mapped Address CM Object. Status = %r\n",
+ __func__,
+ Status
+ ));
+ return Status;
+ }
+
+ if (NumMemDeviceMap == 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: No Memory Device Mapped Address CM Objects found\n",
+ __func__
+ ));
+ return EFI_NOT_FOUND;
+ }
+
+ TableList = (SMBIOS_STRUCTURE **)AllocateZeroPool (
+ sizeof (SMBIOS_STRUCTURE *) * NumMemDeviceMap
+ );
+ if (TableList == NULL) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Failed to allocate memory for %u Memory Device Mapped Address tables\n",
+ __func__,
+ NumMemDeviceMap
+ ));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CmObjectList = (CM_OBJECT_TOKEN *)AllocateZeroPool (
+ sizeof (CM_OBJECT_TOKEN) * NumMemDeviceMap
+ );
+ if (CmObjectList == NULL) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Failed to allocate memory for %u CM Object tokens\n",
+ __func__,
+ NumMemDeviceMap
+ ));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto exitBuildSmbiosType20TableEx;
+ }
+
+ for (Index = 0; Index < NumMemDeviceMap; Index++) {
+ if (MemoryDeviceMapInfo[Index].StartingAddress > MemoryDeviceMapInfo[Index].EndingAddress) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Invalid address range. StartingAddress = 0x%lx, EndingAddress = 0x%lx\n",
+ __func__,
+ MemoryDeviceMapInfo[Index].StartingAddress,
+ MemoryDeviceMapInfo[Index].EndingAddress
+ ));
+ Status = EFI_INVALID_PARAMETER;
+ goto exitBuildSmbiosType20TableEx;
+ }
+
+ if (MemoryDeviceMapInfo[Index].PartitionRowPosition == 0 ) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Invalid PartitionRowPosition. Value must not be 0.\n",
+ __func__
+ ));
+ Status = EFI_INVALID_PARAMETER;
+ goto exitBuildSmbiosType20TableEx;
+ }
+
+ SmbiosRecord = (SMBIOS_TABLE_TYPE20 *)AllocateSmbiosRecord (
+ sizeof (SMBIOS_TABLE_TYPE20),
+ NULL
+ );
+ if (SmbiosRecord == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto exitBuildSmbiosType20TableEx;
+ }
+
+ StartingAddressKb = MemoryDeviceMapInfo[Index].StartingAddress / SIZE_1KB;
+ EndingAddressKb = MemoryDeviceMapInfo[Index].EndingAddress / SIZE_1KB;
+
+ if ((StartingAddressKb >= EXTENDED_ADDRESS_THRESHOLD) ||
+ (EndingAddressKb >= EXTENDED_ADDRESS_THRESHOLD))
+ {
+ SmbiosRecord->StartingAddress = EXTENDED_ADDRESS_THRESHOLD;
+ SmbiosRecord->EndingAddress = EXTENDED_ADDRESS_THRESHOLD;
+ SmbiosRecord->ExtendedStartingAddress = MemoryDeviceMapInfo[Index].StartingAddress;
+ SmbiosRecord->ExtendedEndingAddress = MemoryDeviceMapInfo[Index].EndingAddress;
+ } else {
+ SmbiosRecord->StartingAddress = (UINT32)StartingAddressKb;
+ SmbiosRecord->EndingAddress = (UINT32)EndingAddressKb;
+ }
+
+ if (MemoryDeviceMapInfo[Index].MemoryDeviceInfoToken == CM_NULL_TOKEN) {
+ SmbiosRecord->MemoryDeviceHandle = SMBIOS_HANDLE_INVALID;
+ } else {
+ HandleMap = TableFactoryProtocol->GetSmbiosHandle (
+ MemoryDeviceMapInfo[Index].MemoryDeviceInfoToken
+ );
+ if (HandleMap == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to get Type 17 SMBIOS Handle\n", __func__));
+ Status = EFI_NOT_FOUND;
+ goto exitBuildSmbiosType20TableEx;
+ }
+
+ SmbiosRecord->MemoryDeviceHandle = HandleMap->SmbiosTblHandle;
+ }
+
+ if (MemoryDeviceMapInfo[Index].MemoryArrayMappedAddressToken == CM_NULL_TOKEN) {
+ SmbiosRecord->MemoryArrayMappedAddressHandle = SMBIOS_HANDLE_INVALID;
+ } else {
+ HandleMap = TableFactoryProtocol->GetSmbiosHandle (
+ MemoryDeviceMapInfo[Index].MemoryArrayMappedAddressToken
+ );
+ if (HandleMap == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to get Type 19 SMBIOS Handle\n", __func__));
+ Status = EFI_NOT_FOUND;
+ goto exitBuildSmbiosType20TableEx;
+ }
+
+ SmbiosRecord->MemoryArrayMappedAddressHandle = HandleMap->SmbiosTblHandle;
+ }
+
+ SmbiosRecord->PartitionRowPosition = MemoryDeviceMapInfo[Index].PartitionRowPosition;
+ SmbiosRecord->InterleavePosition = MemoryDeviceMapInfo[Index].InterleavePosition;
+ SmbiosRecord->InterleavedDataDepth = MemoryDeviceMapInfo[Index].InterleavedDataDepth;
+
+ SmbiosRecord->Hdr.Type = EFI_SMBIOS_TYPE_MEMORY_DEVICE_MAPPED_ADDRESS;
+ SmbiosRecord->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE20);
+ TableList[Index] = (SMBIOS_STRUCTURE *)SmbiosRecord;
+ CmObjectList[Index] = MemoryDeviceMapInfo[Index].MemoryDeviceMappedAddressToken;
+
+ SmbiosRecord = NULL;
+ }
+
+ *Table = TableList;
+ *CmObjectToken = CmObjectList;
+ *TableCount = NumMemDeviceMap;
+
+exitBuildSmbiosType20TableEx:
+ if (EFI_ERROR (Status)) {
+ if (TableList != NULL) {
+ for (Index = 0; Index < NumMemDeviceMap; Index++) {
+ if (TableList[Index] != NULL) {
+ FreePool (TableList[Index]);
+ }
+ }
+
+ FreePool (TableList);
+ }
+
+ if (CmObjectList != NULL) {
+ FreePool (CmObjectList);
+ }
+ }
+
+ if (SmbiosRecord != NULL) {
+ FreePool (SmbiosRecord);
+ }
+
+ return Status;
+}
+
+/** The interface for the SMBIOS Type 20 Table Generator.
+*/
+STATIC
+CONST
+SMBIOS_TABLE_GENERATOR SmbiosType20Generator = {
+ // Generator ID
+ CREATE_STD_SMBIOS_TABLE_GEN_ID (EStdSmbiosTableIdType20),
+ // Generator Description
+ L"SMBIOS.TYPE20.GENERATOR",
+ // SMBIOS Table Type
+ SMBIOS_TYPE_MEMORY_DEVICE_MAPPED_ADDRESS,
+ NULL,
+ NULL,
+ // Build table function Extended.
+ BuildSmbiosType20TableEx,
+ // Free function Extended.
+ FreeSmbiosType20TableEx
+};
+
+/** Register the Generator with the SMBIOS 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
+SmbiosType20LibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = RegisterSmbiosTableGenerator (&SmbiosType20Generator);
+ DEBUG ((
+ DEBUG_INFO,
+ "SMBIOS Type 20: Register Generator. Status = %r\n",
+ Status
+ ));
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/** Deregister the Generator from the SMBIOS 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
+SmbiosType20LibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = DeregisterSmbiosTableGenerator (&SmbiosType20Generator);
+ DEBUG ((
+ DEBUG_INFO,
+ "SMBIOS Type 20: Deregister Generator. Status = %r\n",
+ Status
+ ));
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/Smbios/SmbiosType20Lib/SmbiosType20Lib.inf b/DynamicTablesPkg/Library/Smbios/SmbiosType20Lib/SmbiosType20Lib.inf
new file mode 100644
index 0000000000..6c9ccccd75
--- /dev/null
+++ b/DynamicTablesPkg/Library/Smbios/SmbiosType20Lib/SmbiosType20Lib.inf
@@ -0,0 +1,34 @@
+## @file
+# SMBIOS Type20 Table Generator.
+#
+# Copyright (c) 2026, Arm Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = SmbiosType20LibArm
+ FILE_GUID = f55bd2c4-a1dd-4d9b-a0bb-47e32389741f
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_DRIVER
+ CONSTRUCTOR = SmbiosType20LibConstructor
+ DESTRUCTOR = SmbiosType20LibDestructor
+
+[Sources]
+ SmbiosType20Generator.c
+
+[Packages]
+ DynamicTablesPkg/DynamicTablesPkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ MemoryAllocationLib
+ SmbiosStringTableLib
+
+[Protocols]
+ gEdkiiConfigurationManagerProtocolGuid
+ gEdkiiDynamicTableFactoryProtocolGuid