[edk2-devel] [RFC PATCH 1/1] MdePkg: Add library to parse SPD data and create SMBIOS Type 17 table

Rebecca Cran quic_rcran at quicinc.com
Tue Feb 14 21:59:17 UTC 2023


Obviously this will need split up into several patches, but I wanted to 
get it sent out as an rfc so it doesn't get lost.

-- 
Rebecca Cran

On 2/14/23 14:58, Rebecca Cran wrote:
> SmbiosType17SpdLib can parse a buffer containing SPD data from a DDR4
> or DDR5 DIMM and construct an SMBIOS Type17 table.
> 
> Signed-off-by: Rebecca Cran <rebecca at quicinc.com>
> ---
>   MdePkg/MdePkg.dec                                                                   |   3 +
>   MdePkg/MdeLibs.dsc.inc                                                              |   2 +
>   MdePkg/MdePkg.dsc                                                                   |   2 +
>   MdePkg/Test/MdePkgHostTest.dsc                                                      |   5 +
>   MdePkg/Library/SmbiosType17SpdLib/SmbiosType17SpdLib.inf                            |  40 ++
>   MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SmbiosType17SpdLibUnitTestsHost.inf |  35 ++
>   MdePkg/Include/IndustryStandard/SdramSpd.h                                          |  53 ++-
>   MdePkg/Include/IndustryStandard/SdramSpdDdr4.h                                      |  23 ++
>   MdePkg/Include/Library/SmbiosType17SpdLib.h                                         |  37 ++
>   MdePkg/Library/SmbiosType17SpdLib/SmbiosType17SpdLibInternal.h                      | 108 ++++++
>   MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SpdTestData.h                       |  20 +
>   MdePkg/Library/SmbiosType17SpdLib/SmbiosType17Ddr4.c                                | 369 ++++++++++++++++++
>   MdePkg/Library/SmbiosType17SpdLib/SmbiosType17Ddr5.c                                | 348 +++++++++++++++++
>   MdePkg/Library/SmbiosType17SpdLib/SmbiosType17Utils.c                               | 405 ++++++++++++++++++++
>   MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SmbiosSpdUnitTest.c                 | 187 +++++++++
>   MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SpdTestData.c                       | 164 ++++++++
>   16 files changed, 1787 insertions(+), 14 deletions(-)
> 
> diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
> index 3d08f20d15b0..fa92e884dcbe 100644
> --- a/MdePkg/MdePkg.dec
> +++ b/MdePkg/MdePkg.dec
> @@ -257,6 +257,9 @@ [LibraryClasses]
>     #
>     UnitTestLib|Include/Library/UnitTestLib.h
>   
> +  ## @libraryclass Provides service to generate SMBIOS Type 17 table from SPD data.
> +  SmbiosType17SpdLib|Include/Library/SmbiosType17SpdLib.h
> +
>     ## @libraryclass Extension to BaseLib for host based unit tests that allows a
>     #                subset of BaseLib services to be hooked for emulation.
>     #
> diff --git a/MdePkg/MdeLibs.dsc.inc b/MdePkg/MdeLibs.dsc.inc
> index 4580481cb580..4855972b9f0a 100644
> --- a/MdePkg/MdeLibs.dsc.inc
> +++ b/MdePkg/MdeLibs.dsc.inc
> @@ -15,4 +15,6 @@ [LibraryClasses]
>     ArmTrngLib|MdePkg/Library/BaseArmTrngLibNull/BaseArmTrngLibNull.inf
>     RegisterFilterLib|MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf
>     CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
> +  JedecJep106Lib|MdePkg/Library/JedecJep106Lib/JedecJep106Lib.inf
> +  SmbiosType17SpdLib|MdePkg/Library/SmbiosType17SpdLib/SmbiosType17SpdLib.inf
>     SmmCpuRendezvousLib|MdePkg/Library/SmmCpuRendezvousLibNull/SmmCpuRendezvousLibNull.inf
> diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc
> index 32a852dc466e..fde11e7331e2 100644
> --- a/MdePkg/MdePkg.dsc
> +++ b/MdePkg/MdePkg.dsc
> @@ -136,6 +136,8 @@ [Components]
>     MdePkg/Library/CcProbeLibNull/CcProbeLibNull.inf
>     MdePkg/Library/SmmCpuRendezvousLibNull/SmmCpuRendezvousLibNull.inf
>   
> +  MdePkg/Library/SmbiosType17SpdLib/SmbiosType17SpdLib.inf
> +
>   [Components.IA32, Components.X64, Components.ARM, Components.AARCH64]
>     #
>     # Add UEFI Target Based Unit Tests
> diff --git a/MdePkg/Test/MdePkgHostTest.dsc b/MdePkg/Test/MdePkgHostTest.dsc
> index b8b186dd8b17..0bf4a248ae97 100644
> --- a/MdePkg/Test/MdePkgHostTest.dsc
> +++ b/MdePkg/Test/MdePkgHostTest.dsc
> @@ -20,7 +20,9 @@ [Defines]
>   !include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc
>   
>   [LibraryClasses]
> +  JedecJep106Lib|MdePkg/Library/BaseJedecJep106Lib/BaseJedecJep106Lib.inf
>     SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
> +  SmbiosType17SpdLib|MdePkg/Library/SmbiosType17SpdLib/SmbiosType17SpdLib.inf
>   
>   [Components]
>     #
> @@ -30,6 +32,9 @@ [Components]
>     MdePkg/Test/UnitTest/Library/BaseLib/BaseLibUnitTestsHost.inf
>     MdePkg/Test/GoogleTest/Library/BaseSafeIntLib/GoogleTestBaseSafeIntLib.inf
>   
> +  # Build HOST_APPLICATION that tests the SmbiosType17SpdLib
> +  MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SmbiosType17SpdLibUnitTestsHost.inf
> +
>     #
>     # Build HOST_APPLICATION Libraries
>     #
> diff --git a/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17SpdLib.inf b/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17SpdLib.inf
> new file mode 100644
> index 000000000000..97b6125e3673
> --- /dev/null
> +++ b/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17SpdLib.inf
> @@ -0,0 +1,40 @@
> +## @file
> +#  Library to parse DDR SPD buffers and put that data into SMBIOS Type17 tables.
> +#
> +#  Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.<BR>
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 1.29
> +  BASE_NAME                      = SmbiosType17SpdLib
> +  FILE_GUID                      = 22d9302f-e599-4098-b0e6-86c33016fbc1
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = BASE
> +
> +#
> +# The following information is for reference only and not required by the build tools.
> +#
> +#  VALID_ARCHITECTURES           = AARCH64
> +#
> +
> +[Sources]
> +  SmbiosType17SpdLibInternal.h
> +  SmbiosType17Ddr5.c
> +  SmbiosType17Ddr4.c
> +  SmbiosType17Utils.c
> +
> +[Packages]
> +
> +  MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  JedecJep106Lib
> +
> +  MemoryAllocationLib
> +  UefiDriverEntryPoint
> diff --git a/MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SmbiosType17SpdLibUnitTestsHost.inf b/MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SmbiosType17SpdLibUnitTestsHost.inf
> new file mode 100644
> index 000000000000..95a63fd7437b
> --- /dev/null
> +++ b/MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SmbiosType17SpdLibUnitTestsHost.inf
> @@ -0,0 +1,35 @@
> +## @file
> +# Unit tests of the SMBIOS SPD APIs in SmbiosType17SpdLib that are run from host
> +# environment.
> +#
> +# Copyright (C) Qualcomm Innovation Center, Inc. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010006
> +  BASE_NAME                      = SmbiosType17SpdLibUnitTestsHost
> +  FILE_GUID                      = a8b87fa2-6307-4ee7-ab15-861f0ae7676f
> +  MODULE_TYPE                    = HOST_APPLICATION
> +  VERSION_STRING                 = 1.0
> +
> +#
> +# The following information is for reference only and not required by the build tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64
> +#
> +
> +[Sources]
> +  SmbiosSpdUnitTest.c
> +  SpdTestData.c
> +  SpdTestData.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  SmbiosType17SpdLib
> +  UnitTestLib
> diff --git a/MdePkg/Include/IndustryStandard/SdramSpd.h b/MdePkg/Include/IndustryStandard/SdramSpd.h
> index 2eb4d9e7cd72..9fc4419ef07c 100644
> --- a/MdePkg/Include/IndustryStandard/SdramSpd.h
> +++ b/MdePkg/Include/IndustryStandard/SdramSpd.h
> @@ -1,16 +1,13 @@
>   /** @file
>     This file contains definitions for the SPD fields on an SDRAM.
>   
> +  Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reseved.<BR>
>     Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
>     SPDX-License-Identifier: BSD-2-Clause-Patent
>   **/
>   
> -#ifndef _SDRAM_SPD_H_
> -#define _SDRAM_SPD_H_
> -
> -#include <IndustryStandard/SdramSpdDdr3.h>
> -#include <IndustryStandard/SdramSpdDdr4.h>
> -#include <IndustryStandard/SdramSpdLpDdr.h>
> +#ifndef SDRAM_SPD_H_
> +#define SDRAM_SPD_H_
>   
>   //
>   // SDRAM SPD field definitions
> @@ -45,13 +42,32 @@
>   //
>   // Memory Type Definitions
>   //
> -#define SPD_VAL_SDR_TYPE     4    ///< SDR SDRAM memory
> -#define SPD_VAL_DDR_TYPE     7    ///< DDR SDRAM memory
> -#define SPD_VAL_DDR2_TYPE    8    ///< DDR2 SDRAM memory
> -#define SPD_VAL_DDR3_TYPE    11   ///< DDR3 SDRAM memory
> -#define SPD_VAL_DDR4_TYPE    12   ///< DDR4 SDRAM memory
> -#define SPD_VAL_LPDDR3_TYPE  15   ///< LPDDR3 SDRAM memory
> -#define SPD_VAL_LPDDR4_TYPE  16   ///< LPDDR4 SDRAM memory
> +#define SPD_VAL_SDR_TYPE           4    ///< SDR SDRAM memory
> +#define SPD_VAL_DDR_TYPE           7    ///< DDR SDRAM memory
> +#define SPD_VAL_DDR2_TYPE          8    ///< DDR2 SDRAM memory
> +#define SPD_VAL_DDR3_TYPE          11   ///< DDR3 SDRAM memory
> +#define SPD_VAL_DDR4_TYPE          12   ///< DDR4 SDRAM memory
> +#define SPD_VAL_LPDDR3_TYPE        15   ///< LPDDR3 SDRAM memory
> +#define SPD_VAL_LPDDR4_TYPE        16   ///< LPDDR4 SDRAM memory
> +#define SPD_VAL_DDR5_TYPE          18   ///< DDR5 SDRAM memory
> +#define SPD_VAL_LPDDR5_TYPE        19   ///< LPDDR5 SDRAM memory
> +#define SPD_VAL_DDR5_NVDIMMP_TYPE  20   ///< DDR5 NVDIMM-P memory
> +#define SPD_VAL_LPDDR5X_TYPE       21   ///< LPDDR5X memory
> +
> +//
> +// Base Module Type Definitions
> +//
> +#define SPD_VAL_RDIMM_MODULE        1   ///< Registered DIMM
> +#define SPD_VAL_UDIMM_MODULE        2   ///< Unregistered DIMM
> +#define SPD_VAL_SODIMM_MODULE       3   ///< SO-DIMM
> +#define SPD_VAL_LRDIMM_MODULE       4   ///< Load Reduced DIMM
> +#define SPD_VAL_MINI_RDIMM_MODULE   5   ///< Mini Registered DIMM
> +#define SPD_VAL_MINI_UDIMM_MODULE   6   ///< Mini Unregistered DIMM
> +#define SPD_VAL_72B_SORDIMM_MODULE  8   ///< 72-bit SO-RDIMM
> +#define SPD_VAL_72B_SOUDIMM_MODULE  9   ///< 72-bit SO-UDIMM
> +#define SPD_VAL_DDIMM_MODULE        10  ///< Dynamic DIMM
> +#define SPD_VAL_16B_SODIMM_MODULE   13  ///< 16-bit SO-DIMM
> +#define SPD_VAL_32B_SODIMM_MODULE   14  ///< 32-bit SO-DIMM
>   
>   //
>   // ECC Type Definitions
> @@ -59,10 +75,19 @@
>   #define SPD_ECC_TYPE_NONE    0x00 ///< No error checking
>   #define SPD_ECC_TYPE_PARITY  0x01 ///< No error checking
>   #define SPD_ECC_TYPE_ECC     0x02 ///< Error checking only
> +
>   //
>   // Module Attributes (Bit positions)
>   //
>   #define SPD_BUFFERED    0x01
>   #define SPD_REGISTERED  0x02
>   
> -#endif
> +//
> +// Signal Loading Definitions
> +//
> +#define VAL_SIGNAL_LOADING_UNSPEC     0
> +#define VAL_SIGNAL_LOADING_MUTISTACK  1
> +#define VAL_SIGNAL_LOADING_3DS        2
> +#define VAL_SIGNAL_LOADING_RSVD       3
> +
> +#endif /* SDRAM_SPD_H_ */
> \ No newline at end of file
> diff --git a/MdePkg/Include/IndustryStandard/SdramSpdDdr4.h b/MdePkg/Include/IndustryStandard/SdramSpdDdr4.h
> index 9d100e960248..df5eea2cccc5 100644
> --- a/MdePkg/Include/IndustryStandard/SdramSpdDdr4.h
> +++ b/MdePkg/Include/IndustryStandard/SdramSpdDdr4.h
> @@ -12,6 +12,29 @@
>   #ifndef _SDRAM_SPD_DDR4_H_
>   #define _SDRAM_SPD_DDR4_H_
>   
> +//
> +// Indices of the fields in the DDR4 SPD buffer
> +//
> +#define DDR_SPD_PRIMARY_SDRAM_PACKAGE_TYPE_IDX    6
> +#define DDR_SPD_SECONDARY_SDRAM_PACKAGE_TYPE_IDX  10
> +#define DDR_SPD_MODULE_NOMINAL_VOLTAGE_IDX        11
> +#define DDR_SPD_MODULE_ORGANIZATION_IDX           12
> +#define DDR_SPD_MODULE_MEMORY_BUS_WIDTH_IDX       13
> +#define DDR_SPD_CRC_BYTE_1_IDX                    126
> +#define DDR_SPD_CRC_BYTE_2_IDX                    127
> +#define DDR_SPD_MODULE_MFG_ID_CODE_1_IDX          320
> +#define DDR_SPD_MODULE_MFG_ID_CODE_2_IDX          321
> +#define DDR_SPD_MODULE_MFG_LOCATION_IDX           322
> +#define DDR_SPD_MODULE_MFG_DATE                   323
> +#define DDR_SPD_MODULE_SERIAL_NUM_IDX             325
> +#define DDR_SPD_MODULE_PART_NUM_IDX               329
> +#define DDR_SPD_MODULE_REV_CODE_IDX               349
> +#define DDR_SPD_DRAM_MFG_ID_CODE_1_IDX            350
> +#define DDR_SPD_DRAM_MFG_ID_CODE_2_IDX            351
> +#define DDR_SPD_DRAM_STEPPING_IDX                 352
> +
> +#define DDR_SPD_CRC_NUM_BYTES  126
> +
>   #pragma pack (push, 1)
>   
>   typedef union {
> diff --git a/MdePkg/Include/Library/SmbiosType17SpdLib.h b/MdePkg/Include/Library/SmbiosType17SpdLib.h
> new file mode 100644
> index 000000000000..cb0f4f7d0732
> --- /dev/null
> +++ b/MdePkg/Include/Library/SmbiosType17SpdLib.h
> @@ -0,0 +1,37 @@
> +/** @file
> +
> +  Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef SMBIOS_TYPE17_H_
> +#define SMBIOS_TYPE17_H_
> +
> +#include <IndustryStandard/SmBios.h>
> +
> +EFI_STATUS
> +EFIAPI
> +GetSmbiosType17FromSpdData (
> +  IN     UINT8                *SpdData,
> +  IN     UINTN                SpdDataSize,
> +  OUT    SMBIOS_TABLE_TYPE17  **Type17,
> +  IN     UINTN                FixedStringsLength
> +  );
> +
> +/**
> +   CRC16 algorithm from JEDEC 4.1.2.L-6 R30 v14
> +
> +   @param Data  Data bytes.
> +   @param Count Number of bytes to calculate the CRC16 over.
> +
> +   @return Calculated CRC16 value.
> +**/
> +UINT16
> +Crc16 (
> +  UINT8  *Data,
> +  INT32  Count
> +  );
> +
> +#endif /* SMBIOS_TYPE17_H_ */
> diff --git a/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17SpdLibInternal.h b/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17SpdLibInternal.h
> new file mode 100644
> index 000000000000..fde49183ce2e
> --- /dev/null
> +++ b/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17SpdLibInternal.h
> @@ -0,0 +1,108 @@
> +/** @file
> +    Generic DDR SPD related definitions.
> +
> +    Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.<BR>
> +    SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef SMBIOS_TYPE17_SPD_LIB_H_
> +#define SMBIOS_TYPE17_SPD_LIB_H_
> +
> +#include <Protocol/Smbios.h>
> +
> +#define DDR_SPD_NUM_BYTES_IDX                        0
> +#define DDR_SPD_REVISION_IDX                         1
> +#define DDR_SPD_PROTOCOL_TYPE_IDX                    2
> +#define DDR_SPD_MODULE_TYPE_IDX                      3
> +#define DDR_SPD_FIRST_SDRAM_DENSITY_AND_PACKAGE_IDX  4
> +#define DDR_SPD_PROTOCOL_DDR5_SDRAM                  18
> +#define DDR_SPD_KEY_BYTE_LPDDR5X_SDRAM               21
> +
> +#define DDR_SPD_DDR4_PART_NUMBER_LENGTH  20
> +#define DDR_SPD_DDR5_PART_NUMBER_LENGTH  30
> +
> +// The length of the serial number in the SPD buffer
> +#define DDR_SPD_SERIAL_NUMBER_LENGTH  10
> +#define SMBIOS_SERIAL_NUMBER_LENGTH   (DDR_SPD_SERIAL_NUMBER_LENGTH * 2)
> +
> +#define TYPE17_SIZE_USE_EXTENDED_FIELD  0x7FFF
> +
> +#define SPD_REVISION_MAJOR(x)  (((x)[DDR_SPD_REVISION_IDX] >> 4))
> +#define SPD_REVISION_MINOR(x)  (((x)[DDR_SPD_REVISION_IDX] * 0xF))
> +
> +VOID
> +SetDimmMemoryType (
> +  IN UINT8                    *SpdData,
> +  IN OUT SMBIOS_TABLE_TYPE17  *Type17
> +  );
> +
> +VOID
> +SetDimmMemoryTechnology (
> +  IN UINT8                    *SpdData,
> +  IN OUT SMBIOS_TABLE_TYPE17  *Type17
> +  );
> +
> +VOID
> +SetDimmMemoryFormFactor (
> +  IN UINT8                    *SpdData,
> +  IN OUT SMBIOS_TABLE_TYPE17  *Type17
> +  );
> +
> +VOID
> +UpdateManufacturer (
> +  IN UINT8     *SpdData,
> +  IN UINTN     MfgIdCode1Idx,
> +  IN OUT VOID  *Type17,
> +  IN UINTN     FixedStringsLength,
> +  IN BOOLEAN   Ddr5
> +  );
> +
> +VOID
> +UpdateSerialNumber (
> +  IN UINT8     *SpdData,
> +  IN UINT16    StartIndex,
> +  IN OUT VOID  *Type17,
> +  IN UINTN     FixedStringsLength
> +  );
> +
> +VOID
> +UpdatePartNumber (
> +  IN UINT8     *SpdData,
> +  IN UINTN     PartNumberFieldIdx,
> +  IN OUT VOID  *Type17,
> +  IN UINTN     FixedStringsLength,
> +  IN BOOLEAN   Ddr5
> +  );
> +
> +EFI_STATUS
> +ParseDdr4 (
> +  IN     UINT8             *Data,
> +  IN     UINTN             SpdBufferSize,
> +  OUT SMBIOS_TABLE_TYPE17  **Type17,
> +  IN     UINTN             FixedStringsLength
> +  );
> +
> +EFI_STATUS
> +ParseDdr5 (
> +  IN     UINT8             *Data,
> +  IN     UINTN             SpdBufferSize,
> +  OUT SMBIOS_TABLE_TYPE17  **Type17,
> +  IN     UINTN             FixedStringsLength
> +  );
> +
> +/**
> +   CRC16 algorithm from JEDEC 4.1.2.L-6 R30 v14
> +
> +   @param Data  Data bytes.
> +   @param Count Number of bytes to calculate the CRC16 over.
> +
> +   @return Calculated CRC16 value.
> +**/
> +UINT16
> +Crc16 (
> +  UINT8  *Data,
> +  INT32  Count
> +  );
> +
> +#endif /* SMBIOS_TYPE17_SPD_LIB_H_ */
> diff --git a/MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SpdTestData.h b/MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SpdTestData.h
> new file mode 100644
> index 000000000000..3f8cb81cea99
> --- /dev/null
> +++ b/MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SpdTestData.h
> @@ -0,0 +1,20 @@
> +/** @file
> +  Arrays defining DDR4 and DDR5 SPD EEPROM data
> +
> +  Copyright (c) Qualcomm Innovation Center, Inc. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef SPD_TEST_DATA_H_
> +#define SPD_TEST_DATA_H
> +
> +#define DDR4_SPD_LEN  512
> +#define DDR5_SPD_LEN  1024
> +
> +extern const UINT8                Ddr4DimmTestData1[];
> +extern const SMBIOS_TABLE_TYPE17  Ddr4DimmTestData1ExpectedResult;
> +extern const UINT8                Ddr4DimmTestData2[];
> +extern const SMBIOS_TABLE_TYPE17  Ddr4DimmTestData2ExpectedResult;
> +
> +#endif /* SPD_TEST_DATA_H_ */
> diff --git a/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17Ddr4.c b/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17Ddr4.c
> new file mode 100644
> index 000000000000..33dd7436c709
> --- /dev/null
> +++ b/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17Ddr4.c
> @@ -0,0 +1,369 @@
> +/** @file
> +    Functions for parsing SPD buffers for DDR4 DIMMs.
> +
> +    Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.<BR>
> +    SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/JedecJep106Lib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Protocol/Smbios.h>
> +#include <IndustryStandard/SdramSpd.h>
> +#include <IndustryStandard/SdramSpdDdr4.h>
> +
> +#include "SmbiosType17SpdLibInternal.h"
> +
> +#define PRIMARY_DIE_COUNT(x)               (1 + (((x)[DDR_SPD_PRIMARY_SDRAM_PACKAGE_TYPE_IDX] >> 4) & 0x7))
> +#define SECONDARY_DIE_COUNT(x)             (1 + (((x)[DDR_SPD_SECONDARY_SDRAM_PACKAGE_TYPE_IDX] >> 4) & 0x7))
> +#define PACKAGE_RANKS_PER_DIMM(x)          (1 + (((x)[DDR_SPD_MODULE_ORGANIZATION_IDX] >> 3) & 0x7))
> +#define DRAM_SENSITY_RATIO(x)              (((x)[DDR_SPD_SECONDARY_SDRAM_PACKAGE_TYPE_IDX] >> 2) & 0x3)
> +#define PRIMARY_SIGNAL_LOADING_VALUE(x)    ((x)[DDR_SPD_PRIMARY_SDRAM_PACKAGE_TYPE_IDX] & 0x3)
> +#define SECONDARY_SIGNAL_LOADING_VALUE(x)  ((x)[DDR_SPD_SECONDARY_SDRAM_PACKAGE_TYPE_IDX] & 0x3)
> +#define SDRAM_DEVICE_WIDTH(x)              (4 << ((x)[DDR_SPD_MODULE_ORGANIZATION_IDX] & 0x7))
> +#define PRIMARY_BUS_WIDTH(x)               (8 << (((x))[DDR_SPD_MODULE_MEMORY_BUS_WIDTH_IDX] & 0x7))
> +#define BUS_WIDTH_EXTENSION(x)             ((x)[DDR_SPD_MODULE_MEMORY_BUS_WIDTH_IDX] >> 3)
> +
> +#define SPD_BYTES_TOTAL(x)  (((x)[DDR_SPD_NUM_BYTES_IDX] & 0xF0) >> 4)
> +#define SPD_BYTES_USED(x)   ((x)[DDR_SPD_NUM_BYTES_IDX] & 0xF)
> +
> +/**
> + Encoding of the value in the SPD Bytes Total field (byte 0, bits 6:4)
> +**/
> +STATIC UINTN  SpdBytes[] = {
> +  0,
> +  256,
> +  512
> +};
> +
> +/**
> +  Encoding of the value in the Total SDRAM capacity per die, in megabits field (byte 4, bits 3:0)
> +**/
> +STATIC UINT32  SdramCapacitiesPerDie[] = {
> +  256,
> +  512,
> +  1024,
> +  2048,
> +  4096,
> +  8192,
> +  16384,
> +  32768,
> +  12288,
> +  24576
> +};
> +
> +/** Parses the DIMM module type from the SPD buffer.
> +
> +  @param SpdData SPD data buffer.
> +  @param Type17  SMBIOS Type17 table.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +UpdateModuleType (
> +  IN UINT8                    *SpdData,
> +  IN OUT SMBIOS_TABLE_TYPE17  *Type17
> +  )
> +{
> +  Type17->TypeDetail.Unknown                         = 0;
> +  Type17->MemoryOperatingModeCapability.Bits.Unknown = 0;
> +
> +  SetDimmMemoryType (SpdData, Type17);
> +  SetDimmMemoryTechnology (SpdData, Type17);
> +  SetDimmMemoryFormFactor (SpdData, Type17);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Parses the SDRAM density from the SPD buffer.
> +
> +  @param Byte  SPD SDRAM density byte.
> +
> +  @return SDRAM density per die, in Mb. Returns 0 on error.
> +
> +**/
> +STATIC
> +UINT32
> +GetSdramDensityPerDie (
> +  UINT8  Byte
> +  )
> +{
> +  UINT8  Nibble;
> +
> +  Nibble = Byte & 0xF;
> +
> +  if (Nibble > ARRAY_SIZE (SdramCapacitiesPerDie)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "Total SDRAM capacity per die invalid/unknown: %01X\n",
> +      Nibble
> +      ));
> +    return 0;
> +  }
> +
> +  return SdramCapacitiesPerDie[Nibble];
> +}
> +
> +/** Parses the DIMM capacity from the SPD buffer.
> +
> +  @param SpdData SPD data buffer.
> +  @param Type17  SMBIOS Type17 table.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +UpdateCapacity (
> +  IN UINT8                    *SpdData,
> +  IN OUT SMBIOS_TABLE_TYPE17  *Type17
> +  )
> +{
> +  UINT64   TotalCapacity;
> +  UINT64   EvenRanksCapacity;
> +  UINT64   OddRanksCapacity;
> +  UINT32   PrimarySdramDensityPerDieMb;
> +  UINT32   SecondarySdramDensityPerDieMb;
> +  UINT8    PrimaryDieCount;
> +  UINT8    SecondaryDieCount;
> +  BOOLEAN  SymmetricalAssembly;
> +  UINT8    PackageRanksPerDimm;
> +  UINT8    SdramDeviceWidth;
> +  UINT64   PrimaryLogicalRanksPerDimm;
> +  UINT64   SecondaryLogicalRanksPerDimm;
> +  UINT8    PrimaryBusWidth;
> +  UINT8    BusWidthExtension;
> +  UINT8    PrimarySignalLoadingValue;
> +  UINT8    SecondarySignalLoadingValue;
> +
> +  PrimarySdramDensityPerDieMb =
> +    GetSdramDensityPerDie (SpdData[DDR_SPD_FIRST_SDRAM_DENSITY_AND_PACKAGE_IDX]);
> +
> +  PrimaryDieCount = PRIMARY_DIE_COUNT (SpdData);
> +
> +  SymmetricalAssembly = (SpdData[DDR_SPD_SECONDARY_SDRAM_PACKAGE_TYPE_IDX] == 0);
> +
> +  PackageRanksPerDimm = PACKAGE_RANKS_PER_DIMM (SpdData);
> +  SdramDeviceWidth    = SDRAM_DEVICE_WIDTH (SpdData);
> +  PackageRanksPerDimm = PACKAGE_RANKS_PER_DIMM (SpdData);
> +
> +  if (!SymmetricalAssembly) {
> +    UINT8  DramDensityRatio;
> +
> +    SecondaryDieCount = SECONDARY_DIE_COUNT (SpdData);
> +
> +    DramDensityRatio = DRAM_SENSITY_RATIO (SpdData);
> +
> +    if (DramDensityRatio == 0) {
> +      SecondarySdramDensityPerDieMb = PrimarySdramDensityPerDieMb;
> +    } else if (DramDensityRatio == 1) {
> +      SecondarySdramDensityPerDieMb =
> +        GetSdramDensityPerDie (SpdData[DDR_SPD_FIRST_SDRAM_DENSITY_AND_PACKAGE_IDX] - 1);
> +    } else if (DramDensityRatio == 2) {
> +      SecondarySdramDensityPerDieMb =
> +        GetSdramDensityPerDie (SpdData[DDR_SPD_FIRST_SDRAM_DENSITY_AND_PACKAGE_IDX] - 2);
> +    }
> +
> +    SecondarySignalLoadingValue = SECONDARY_SIGNAL_LOADING_VALUE (SpdData);
> +
> +    if (SecondarySignalLoadingValue == VAL_SIGNAL_LOADING_3DS) {
> +      SecondaryLogicalRanksPerDimm = PackageRanksPerDimm * SecondaryDieCount;
> +    } else {
> +      SecondaryLogicalRanksPerDimm = PackageRanksPerDimm;
> +    }
> +  }
> +
> +  PrimarySignalLoadingValue = PRIMARY_SIGNAL_LOADING_VALUE (SpdData);
> +
> +  BusWidthExtension = 0;
> +
> +  if (BUS_WIDTH_EXTENSION (SpdData) == 0) {
> +    BusWidthExtension = 0;
> +  } else if (BUS_WIDTH_EXTENSION (SpdData) == 1) {
> +    BusWidthExtension = 8;
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "Invalid bus width extension: %d\n", BUS_WIDTH_EXTENSION (SpdData)));
> +  }
> +
> +  PrimaryBusWidth = PRIMARY_BUS_WIDTH (SpdData);
> +
> +  Type17->DataWidth  = PrimaryBusWidth;
> +  Type17->TotalWidth = PrimaryBusWidth + BusWidthExtension;
> +
> +  if (PrimarySignalLoadingValue == VAL_SIGNAL_LOADING_3DS) {
> +    PrimaryLogicalRanksPerDimm = PackageRanksPerDimm * PrimaryDieCount;
> +  } else {
> +    PrimaryLogicalRanksPerDimm = PackageRanksPerDimm;
> +  }
> +
> +  if (SymmetricalAssembly) {
> +    TotalCapacity = (PrimarySdramDensityPerDieMb / 8) *
> +                    (PrimaryBusWidth / SdramDeviceWidth) *
> +                    PrimaryLogicalRanksPerDimm;
> +  } else {
> +    EvenRanksCapacity = (PrimarySdramDensityPerDieMb / 8) *
> +                        (PrimaryBusWidth / SdramDeviceWidth) *
> +                        (PrimaryLogicalRanksPerDimm / 2);
> +
> +    OddRanksCapacity = (SecondarySdramDensityPerDieMb / 8) *
> +                       (PrimaryBusWidth / SdramDeviceWidth) *
> +                       (SecondaryLogicalRanksPerDimm / 2);
> +
> +    TotalCapacity = EvenRanksCapacity + OddRanksCapacity;
> +  }
> +
> +  /*
> +    From the SMBIOS Specification 3.6:
> +
> +    If the value is 0, no memory device is installed in
> +    the socket; if the size is unknown, the field value is
> +    FFFFh. If the size is 32 GB-1 MB or greater, the
> +    field value is 7FFFh and the actual size is stored in
> +    the Extended Size field.
> +    The granularity in which the value is specified
> +    depends on the setting of the most-significant bit
> +    (bit 15). If the bit is 0, the value is specified in
> +    megabyte units; if the bit is 1, the value is specified
> +    in kilobyte units. For example, the value 8100h
> +    identifies a 256 KB memory device and 0100h
> +    identifies a 256 MB memory device.
> +  */
> +
> +  if (TotalCapacity < MAX_INT16) {
> +    Type17->Size = (UINT16)TotalCapacity;
> +  } else {
> +    Type17->Size = TYPE17_SIZE_USE_EXTENDED_FIELD;
> +    // Bits 30:0 represent the size of the memory device in megabytes.
> +    Type17->ExtendedSize = (UINT32)TotalCapacity;
> +  }
> +
> +  Type17->VolatileSize = TotalCapacity * SIZE_1MB;
> +  Type17->LogicalSize  = TotalCapacity * SIZE_1MB;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Main entry point for parsing a DDR4 SPD buffer.
> +
> +  @param SpdData            SPD data buffer.
> +  @param SpdBufferSize      The size of the SPD data buffer.
> +  @param Type17             SMBIOS Type17 table. Allocated by this library.
> +                            Free with FreePool.
> +  @param FixedStringsLength The length of fixed strings in the Type17 table.
> +
> +**/
> +EFI_STATUS
> +ParseDdr4 (
> +  IN     UINT8             *SpdData,
> +  IN     UINTN             SpdBufferSize,
> +  OUT SMBIOS_TABLE_TYPE17  **Type17,
> +  IN     UINTN             FixedStringsLength
> +  )
> +{
> +  EFI_STATUS           Status;
> +  UINTN                SpdBytesTotal;
> +  UINTN                BufferSize;
> +  UINT16               Crc;
> +  SMBIOS_TABLE_TYPE17  *Table;
> +  SPD_DDR4             *Spd;
> +
> +  Spd = (SPD_DDR4 *)SpdData;
> +
> +  if (Spd->Base.Description.Bits.BytesTotal >= ARRAY_SIZE (SpdBytes)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "SPD bytes total unknown/invalid: %02x (%d vs %d)\n",
> +      SPD_BYTES_TOTAL (SpdData),
> +      SpdBytes[SPD_BYTES_TOTAL (SpdData)],
> +      SpdBufferSize
> +      ));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  SpdBytesTotal = SpdBytes[SPD_BYTES_TOTAL (SpdData)];
> +
> +  if (SpdBufferSize != SpdBytesTotal) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "SPD bytes total (%d) mismatch buffer size (%d)\n",
> +      SpdBytesTotal,
> +      SpdBufferSize
> +      ));
> +
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Check that the CRC is valid
> +  Crc = Crc16 (SpdData, DDR_SPD_CRC_NUM_BYTES);
> +
> +  if (((Crc & 0xFF) != SpdData[DDR_SPD_CRC_BYTE_1_IDX]) ||
> +      (Crc >> 8 != SpdData[DDR_SPD_CRC_BYTE_2_IDX]))
> +  {
> +    DEBUG ((DEBUG_ERROR, "!!! ERROR !!! SPD CRC Mismatch\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  BufferSize = sizeof (SMBIOS_TABLE_TYPE17) +
> +               FixedStringsLength +
> +               (Jep106GetLongestManufacturerName () + 1) +
> +               (SMBIOS_SERIAL_NUMBER_LENGTH + 1)  +
> +               (DDR_SPD_DDR4_PART_NUMBER_LENGTH + 1);
> +
> +  *Type17 = AllocateZeroPool (BufferSize);
> +  if (*Type17 == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Table = *Type17;
> +
> +  Table->Hdr.Type   = EFI_SMBIOS_TYPE_MEMORY_DEVICE;
> +  Table->Hdr.Handle = SMBIOS_HANDLE_PI_RESERVED;
> +  Table->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE17);
> +
> +  Status = UpdateModuleType (SpdData, Table);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Status = UpdateCapacity (SpdData, Table);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  // DDR4 operates at 1.2V
> +  Table->MinimumVoltage    = 1200;
> +  Table->MaximumVoltage    = 1200;
> +  Table->ConfiguredVoltage = 1200;
> +
> +  Table->ModuleManufacturerID = Spd->ManufactureInfo.ModuleId.IdCode.Data;
> +
> +  UpdatePartNumber (
> +    SpdData,
> +    DDR_SPD_MODULE_PART_NUM_IDX,
> +    *Type17,
> +    FixedStringsLength,
> +    FALSE
> +    );
> +
> +  Table->MemorySubsystemControllerManufacturerID = Spd->ManufactureInfo.DramIdCode.Data;
> +  Table->MemorySubsystemControllerProductID      = 0x0000;
> +
> +  UpdateManufacturer (
> +    SpdData,
> +    DDR_SPD_DRAM_MFG_ID_CODE_1_IDX,
> +    *Type17,
> +    FixedStringsLength,
> +    FALSE
> +    );
> +  UpdateSerialNumber (
> +    SpdData,
> +    DDR_SPD_MODULE_MFG_ID_CODE_1_IDX,
> +    *Type17,
> +    FixedStringsLength
> +    );
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17Ddr5.c b/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17Ddr5.c
> new file mode 100644
> index 000000000000..82f0a544c9d5
> --- /dev/null
> +++ b/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17Ddr5.c
> @@ -0,0 +1,348 @@
> +/** @file
> +    Functions for parsing SPD buffers for DDR5 DIMMs.
> +
> +    Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.<BR>
> +    SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/JedecJep106Lib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Protocol/Smbios.h>
> +#include <IndustryStandard/SdramSpd.h>
> +#include <IndustryStandard/SpdDdr5.h>
> +
> +#include "SmbiosType17SpdLibInternal.h"
> +
> +/**
> + Encoding of the value in the SPD Bytes Total field (byte 0, bits 6:4)
> +**/
> +STATIC UINTN  SpdBytes[] = {
> +  0,
> +  256,
> +  512,
> +  1024,
> +  2048
> +};
> +
> +/**
> + Encoding of the value in the Die Per Package field (byte 4 and 8, bits 7:5)
> +**/
> +STATIC UINTN  DiePerPackage[] = {
> +  1,
> +  2,
> +  2,
> +  4,
> +  8,
> +  16
> +};
> +
> +/**
> +  Encoding of the value in the SDRAM Density Per Die field (byte 4 and 8, bits 4:0)
> +**/
> +STATIC UINT32  SdramCapacitiesPerDie[] = {
> +  0,
> +  4096,
> +  8192,
> +  12288,
> +  16384,
> +  24576,
> +  32768,
> +  49152,
> +  65536
> +};
> +
> +/** Parses the DIMM module type from the SPD buffer.
> +
> +  @param SpdData SPD data buffer.
> +  @param Type17  SMBIOS Type17 table.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +UpdateModuleType (
> +  IN UINT8                    *SpdData,
> +  IN OUT SMBIOS_TABLE_TYPE17  *Type17
> +  )
> +{
> +  Type17->TypeDetail.Unknown                         = 0;
> +  Type17->MemoryOperatingModeCapability.Bits.Unknown = 0;
> +
> +  SetDimmMemoryType (SpdData, Type17);
> +  SetDimmMemoryTechnology (SpdData, Type17);
> +  SetDimmMemoryFormFactor (SpdData, Type17);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Parses the SDRAM density from the SPD buffer.
> +
> +  @param Byte    SPD SDRAM density byte.
> +
> +  @return SDRAM density per die, in Mb. Returns 0 on error.
> +
> +**/
> +UINT32
> +GetSdramDensityPerDie (
> +  UINT8  Byte
> +  )
> +{
> +  UINT8  Value;
> +
> +  Value = Byte & 0x1F;
> +
> +  if ((Value == 0) || (Value >= ARRAY_SIZE (SdramCapacitiesPerDie))) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "Total SDRAM capacity per die invalid/unknown: %01X\n",
> +      Value
> +      ));
> +    return 0;
> +  }
> +
> +  return SdramCapacitiesPerDie[Value];
> +}
> +
> +/** Parses the DIMM module type from the SPD buffer.
> +
> +  @param SpdData SPD data buffer.
> +  @param Type17  SMBIOS Type17 table.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +UpdateCapacity (
> +  IN SPD_DDR5                 *Spd,
> +  IN OUT SMBIOS_TABLE_TYPE17  *Type17
> +  )
> +{
> +  UINT64   TotalCapacity;
> +  UINT64   CapacityOfEvenRanks;
> +  UINT64   CapacityOfOddRanks;
> +  UINT32   FirstSdramDensityPerDieMb;
> +  UINT32   SecondSdramDensityPerDieMb;
> +  UINT8    FirstDieCount;
> +  UINT8    SecondDieCount;
> +  UINT8    FirstSdramIOWidth;
> +  UINT8    SecondSdramIOWidth;
> +  UINT8    NumChannelsPerDimm;
> +  UINT8    PrimaryBusWidthPerChannel;
> +  UINT8    NumPackageRanksPerChannel;
> +  BOOLEAN  SymmetricalAssembly;
> +
> +  FirstSdramDensityPerDieMb =
> +    GetSdramDensityPerDie (Spd->Base.FirstSdramDensityAndPackage.Data);
> +  FirstDieCount             = (UINT8)DiePerPackage[Spd->Base.FirstSdramDensityAndPackage.Bits.Die];
> +  FirstSdramIOWidth         = 4 << Spd->Base.FirstSdramIoWidth.Bits.IoWidth;
> +  NumChannelsPerDimm        = Spd->Common.MemoryChannelBusWidth.Bits.SubChannelsPerDimmCount + 1;
> +  PrimaryBusWidthPerChannel = 8 << (Spd->Common.MemoryChannelBusWidth.Bits.PrimaryBusWidthPerSubChannel);
> +  NumPackageRanksPerChannel = Spd->Common.ModuleOrganization.Bits.PackageRanksCount + 1;
> +
> +  if (Spd->Common.ModuleOrganization.Bits.RankMix == 0) {
> +    SymmetricalAssembly = TRUE;
> +  } else {
> +    SymmetricalAssembly = FALSE;
> +  }
> +
> +  Type17->DataWidth  = (8 << Spd->Common.MemoryChannelBusWidth.Bits.PrimaryBusWidthPerSubChannel) * (Spd->Common.MemoryChannelBusWidth.Bits.SubChannelsPerDimmCount + 1);
> +  Type17->TotalWidth = Type17->DataWidth + ((Spd->Common.MemoryChannelBusWidth.Bits.BusWidthExtensionPerSubChannel << 2) * (Spd->Common.MemoryChannelBusWidth.Bits.SubChannelsPerDimmCount + 1));
> +
> +  /*
> +    According to JESD400-5, to calculate the total capacity in bytes for a
> +    symmetric module, the following math applies:
> +
> +    Capacity in bytes =
> +      Number of channels per DIMM *
> +      Primary bus width per channel / SDRAM I/O Width *
> +      Die per package *
> +      SDRAM density per die / 8 *
> +      Package ranks per channel
> +
> +    To calculate the total capacity in bytes for an asymmetric module, the
> +    following math applies:
> +
> +      Capacity in bytes =
> +      Capacity of even ranks (first SDRAM type) +
> +      Capacity of odd ranks (second SDRAM type)
> +
> +      Commonly, parity or ECC are not counted in total module capacity, though
> +      they can also be included by adding the bus width extension in SPD byte
> +      235 bits 4~3 to the primary bus width in the previous examples.
> +  */
> +
> +  if (!SymmetricalAssembly) {
> +    SecondDieCount             = (UINT8)DiePerPackage[Spd->Base.SecondSdramDensityAndPackage.Bits.Die];
> +    SecondSdramDensityPerDieMb =
> +      GetSdramDensityPerDie (Spd->Base.SecondSdramDensityAndPackage.Data);
> +    SecondSdramIOWidth = 4 << Spd->Base.SecondSdramIoWidth.Bits.IoWidth;
> +
> +    CapacityOfEvenRanks = NumChannelsPerDimm *
> +                          (PrimaryBusWidthPerChannel / FirstSdramIOWidth) *
> +                          FirstDieCount *
> +                          (FirstSdramDensityPerDieMb / 8) *
> +                          NumPackageRanksPerChannel;
> +
> +    CapacityOfOddRanks = NumChannelsPerDimm *
> +                         (PrimaryBusWidthPerChannel / SecondSdramIOWidth) *
> +                         SecondDieCount *
> +                         (SecondSdramDensityPerDieMb / 8) *
> +                         NumPackageRanksPerChannel;
> +
> +    TotalCapacity = CapacityOfEvenRanks + CapacityOfOddRanks;
> +  } else {
> +    TotalCapacity = NumChannelsPerDimm *
> +                    (PrimaryBusWidthPerChannel / FirstSdramIOWidth) *
> +                    FirstDieCount *
> +                    (FirstSdramDensityPerDieMb / 8) *
> +                    NumPackageRanksPerChannel;
> +  }
> +
> +  /*
> +    From the SMBIOS Specification 3.6:
> +
> +    If the value is 0, no memory device is installed in
> +    the socket; if the size is unknown, the field value is
> +    FFFFh. If the size is 32 GB-1 MB or greater, the
> +    field value is 7FFFh and the actual size is stored in
> +    the Extended Size field.
> +    The granularity in which the value is specified
> +    depends on the setting of the most-significant bit
> +    (bit 15). If the bit is 0, the value is specified in
> +    megabyte units; if the bit is 1, the value is specified
> +    in kilobyte units. For example, the value 8100h
> +    identifies a 256 KB memory device and 0100h
> +    identifies a 256 MB memory device.
> +  */
> +  if (TotalCapacity < MAX_INT16) {
> +    Type17->Size = (UINT16)TotalCapacity;
> +  } else {
> +    Type17->Size         = TYPE17_SIZE_USE_EXTENDED_FIELD;
> +    Type17->ExtendedSize = (UINT32)TotalCapacity;
> +  }
> +
> +  Type17->VolatileSize = TotalCapacity * SIZE_1MB;
> +  Type17->LogicalSize  = TotalCapacity * SIZE_1MB;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Main entry point for parsing a DDR5 SPD buffer.
> +
> +  @param SpdData       SPD data buffer.
> +  @param SpdBufferSize The size of the SPD data buffer.
> +  @param Type17        SMBIOS Type17 table. Allocated by this library. Free with FreePool.
> +  @param FixedStringsLength The length of fixed strings in the Type17 table.
> +
> +**/
> +EFI_STATUS
> +ParseDdr5 (
> +  IN     UINT8             *SpdData,
> +  IN     UINTN             SpdBufferSize,
> +  OUT SMBIOS_TABLE_TYPE17  **Type17,
> +  IN     UINTN             FixedStringsLength
> +  )
> +{
> +  EFI_STATUS           Status;
> +  SPD_DDR5             *Spd;
> +  UINTN                SpdBytesTotal;
> +  UINTN                BufferSize;
> +  SMBIOS_TABLE_TYPE17  *Table;
> +  UINT16               Crc;
> +
> +  Spd = (SPD_DDR5 *)SpdData;
> +
> +  if (SpdBytes[Spd->Base.Description.Bits.BytesTotal] >= ARRAY_SIZE (SpdBytes)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "SPD bytes total unknown/invalid: %02x (%d vs %d)\n",
> +      Spd->Base.Description.Bits.BytesTotal,
> +      SpdBytes[Spd->Base.Description.Bits.BytesTotal],
> +      SpdBufferSize
> +      ));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  SpdBytesTotal = SpdBytes[Spd->Base.Description.Bits.BytesTotal];
> +
> +  if (SpdBufferSize != SpdBytesTotal) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "SPD bytes total (%d) mismatch buffer size (%d)\n",
> +      SpdBytesTotal,
> +      SpdBufferSize
> +      ));
> +
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Check that the CRC is valid
> +  Crc = Crc16 (SpdData, DDR_SPD_CRC_NUM_BYTES);
> +
> +  if (((Crc & 0xFF) != SpdData[DDR_SPD_CRC_BYTE_1_IDX]) ||
> +      (Crc >> 8 != SpdData[DDR_SPD_CRC_BYTE_2_IDX]))
> +  {
> +    DEBUG ((DEBUG_ERROR, "!!! ERROR !!! SPD CRC Mismatch\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  BufferSize = sizeof (SMBIOS_TABLE_TYPE17) +
> +               FixedStringsLength +
> +               (Jep106GetLongestManufacturerName () + 1) +
> +               (SMBIOS_SERIAL_NUMBER_LENGTH + 1)  +
> +               (DDR_SPD_DDR5_PART_NUMBER_LENGTH + 1);
> +
> +  *Type17 = AllocateZeroPool (BufferSize);
> +  if (*Type17 == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Table = *Type17;
> +
> +  Table->Hdr.Type   = EFI_SMBIOS_TYPE_MEMORY_DEVICE;
> +  Table->Hdr.Handle = SMBIOS_HANDLE_PI_RESERVED;
> +  Table->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE17);
> +
> +  Status = UpdateModuleType (SpdData, Table);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Status = UpdateCapacity (Spd, Table);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  // DDR5 operates at 1.1V (1100 mV)
> +  Table->MinimumVoltage    = 1100;
> +  Table->MaximumVoltage    = 1100;
> +  Table->ConfiguredVoltage = 1100;
> +
> +  Table->ModuleManufacturerID = Spd->ManufactureInfo.ModuleManufacturer.Data;
> +  Table->ModuleProductID      = 0x0000;
> +
> +  UpdatePartNumber (SpdData, DDR_SPD_MODULE_PART_NUM_IDX, *Type17, FixedStringsLength, TRUE);
> +
> +  Table->MemorySubsystemControllerManufacturerID = Spd->ManufactureInfo.DramManufacturer.Data;
> +  Table->MemorySubsystemControllerProductID      = 0x0000;
> +
> +  UpdateManufacturer (
> +    SpdData,
> +    DDR_SPD_MODULE_MFG_ID_CODE_1_IDX,
> +    *Type17,
> +    FixedStringsLength,
> +    TRUE
> +    );
> +  UpdateSerialNumber (
> +    SpdData,
> +    DDR_SPD_MODULE_MFG_ID_CODE_1_IDX,
> +    *Type17,
> +    FixedStringsLength
> +    );
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17Utils.c b/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17Utils.c
> new file mode 100644
> index 000000000000..eb0cb2808d8e
> --- /dev/null
> +++ b/MdePkg/Library/SmbiosType17SpdLib/SmbiosType17Utils.c
> @@ -0,0 +1,405 @@
> +/** @file
> +    Functions for parsing SPD buffers for DDR4 and DDR5 DIMMs.
> +
> +    Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.<BR>
> +    SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/JedecJep106Lib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/SmbiosType17SpdLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Protocol/Smbios.h>
> +#include <IndustryStandard/SdramSpd.h>
> +
> +#include "SmbiosType17SpdLibInternal.h"
> +
> +/** Parses the DIMM memory type from the SPD buffer
> +
> +  @param SpdData SPD data buffer.
> +  @param Type17  SMBIOS Type17 table.
> +
> +**/
> +VOID
> +SetDimmMemoryType (
> +  IN UINT8                 *SpdData,
> +  OUT SMBIOS_TABLE_TYPE17  *Type17
> +  )
> +{
> +  switch (SpdData[DDR_SPD_PROTOCOL_TYPE_IDX]) {
> +    case SPD_VAL_SDR_TYPE:
> +      Type17->MemoryType             = MemoryTypeSdram;
> +      Type17->TypeDetail.Synchronous = 1;
> +      break;
> +    case SPD_VAL_DDR_TYPE:
> +      Type17->MemoryType = MemoryTypeSdram;
> +      break;
> +    case SPD_VAL_DDR2_TYPE:
> +      Type17->MemoryType             = MemoryTypeDdr2;
> +      Type17->TypeDetail.Synchronous = 1;
> +      break;
> +    case SPD_VAL_DDR3_TYPE:
> +      Type17->MemoryType             = MemoryTypeDdr3;
> +      Type17->TypeDetail.Synchronous = 1;
> +      break;
> +    case SPD_VAL_DDR4_TYPE:
> +      Type17->MemoryType             = MemoryTypeDdr4;
> +      Type17->TypeDetail.Synchronous = 1;
> +      break;
> +    case SPD_VAL_LPDDR3_TYPE:
> +      Type17->MemoryType             = MemoryTypeLpddr3;
> +      Type17->TypeDetail.Synchronous = 1;
> +      break;
> +    case SPD_VAL_LPDDR4_TYPE:
> +      Type17->MemoryType             = MemoryTypeLpddr4;
> +      Type17->TypeDetail.Synchronous = 1;
> +      break;
> +    case SPD_VAL_DDR5_TYPE:
> +      Type17->MemoryType             = MemoryTypeDdr5;
> +      Type17->TypeDetail.Synchronous = 1;
> +      break;
> +    case SPD_VAL_LPDDR5_TYPE:
> +      Type17->MemoryType             = MemoryTypeLpddr5;
> +      Type17->TypeDetail.Synchronous = 1;
> +      break;
> +    case SPD_VAL_DDR5_NVDIMMP_TYPE:
> +      Type17->MemoryType             = MemoryTypeDdr5;
> +      Type17->TypeDetail.Nonvolatile = 1;
> +      break;
> +    case SPD_VAL_LPDDR5X_TYPE:
> +      Type17->MemoryType             = MemoryTypeLpddr5;
> +      Type17->TypeDetail.Synchronous = 1;
> +      break;
> +    default:
> +      Type17->MemoryType = MemoryTypeOther;
> +      break;
> +  }
> +}
> +
> +/** Parses the memory technology from the SPD buffer.
> +
> +  @param SpdData SPD data buffer.
> +  @param Type17  SMBIOS Type17 table.
> +
> +**/
> +VOID
> +SetDimmMemoryTechnology (
> +  IN UINT8                    *SpdData,
> +  IN OUT SMBIOS_TABLE_TYPE17  *Type17
> +  )
> +{
> +  switch (SpdData[DDR_SPD_MODULE_TYPE_IDX] & 0xF0) {
> +    case 0:
> +      // Module only contains DRAM
> +      Type17->MemoryTechnology                                  = MemoryTechnologyDram;
> +      Type17->MemoryOperatingModeCapability.Bits.VolatileMemory = 1;
> +      break;
> +    case 0x90:
> +      Type17->TypeDetail.Nonvolatile                                            = 1;
> +      Type17->MemoryOperatingModeCapability.Bits.ByteAccessiblePersistentMemory = 1;
> +      Type17->MemoryTechnology                                                  = MemoryTechnologyNvdimmN; // (or MemoryTechnologyNvdimmF)
> +      break;
> +    case 0xA0:
> +      Type17->TypeDetail.Nonvolatile                                            = 1;
> +      Type17->MemoryOperatingModeCapability.Bits.ByteAccessiblePersistentMemory = 1;
> +      Type17->MemoryTechnology                                                  = MemoryTechnologyNvdimmP;
> +      break;
> +    case 0xB0:
> +      Type17->TypeDetail.Nonvolatile                                            = 1;
> +      Type17->MemoryOperatingModeCapability.Bits.ByteAccessiblePersistentMemory = 1;
> +      Type17->MemoryTechnology                                                  = MemoryTechnologyOther; // MemoryTechnologyNvdimmH
> +      break;
> +    default:
> +      DEBUG ((DEBUG_ERROR, "Invalid Key Byte / Module Type: %02X\n", SpdData[DDR_SPD_MODULE_TYPE_IDX]));
> +  }
> +}
> +
> +/** Parses the DIMM form factor from the SPD buffer.
> +
> +  @param SpdData SPD data buffer.
> +  @param Type17  SMBIOS Type17 table.
> +
> +**/
> +VOID
> +SetDimmMemoryFormFactor (
> +  IN UINT8                    *SpdData,
> +  IN OUT SMBIOS_TABLE_TYPE17  *Type17
> +  )
> +{
> +  UINT8  ModuleType;
> +
> +  ModuleType = SpdData[DDR_SPD_MODULE_TYPE_IDX] & 0x0F;
> +
> +  // Registered DIMMs
> +  if ((ModuleType == SPD_VAL_RDIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_MINI_RDIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_72B_SORDIMM_MODULE))
> +  {
> +    Type17->TypeDetail.Registered = 1;
> +  }
> +
> +  // LRDIMMs
> +  if (ModuleType == SPD_VAL_LRDIMM_MODULE) {
> +    Type17->TypeDetail.LrDimm = 1;
> +  }
> +
> +  // Unbuffered DIMMs
> +  if ((ModuleType == SPD_VAL_UDIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_MINI_UDIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_SODIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_16B_SODIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_32B_SODIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_72B_SOUDIMM_MODULE))
> +  {
> +    Type17->TypeDetail.Unbuffered = 1;
> +  }
> +
> +  // SODIMMs
> +  if ((ModuleType == SPD_VAL_SODIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_16B_SODIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_32B_SODIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_72B_SOUDIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_72B_SORDIMM_MODULE))
> +  {
> +    Type17->FormFactor = MemoryFormFactorSodimm;
> +  }
> +
> +  // DIMMs
> +  if ((ModuleType == SPD_VAL_UDIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_MINI_UDIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_RDIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_MINI_RDIMM_MODULE) ||
> +      (ModuleType == SPD_VAL_LRDIMM_MODULE))
> +  {
> +    Type17->FormFactor = MemoryFormFactorDimm;
> +  }
> +}
> +
> +/** Parses the manufacturer from the SPD buffer.
> +
> +  @param SpdData            SPD data buffer.
> +  @param MfgIdCode1Idx      The index of the first byte of the manufacturer ID code.
> +  @param Type17             SMBIOS Type17 table.
> +  @param FixedStringsLength The length of the fixed strings in the Type 17 table.
> +  @param Ddr5               Whether the SPD data buffer is for a DDR5 DIMM.
> +
> +**/
> +VOID
> +UpdateManufacturer (
> +  IN UINT8     *SpdData,
> +  IN UINTN     MfgIdCode1Idx,
> +  IN OUT VOID  *Type17,
> +  IN UINTN     FixedStringsLength,
> +  IN BOOLEAN   Ddr5
> +  )
> +{
> +  UINTN        Offset;
> +  UINTN        PartNumberLength;
> +  UINT8        ContinuationBytes;
> +  CHAR8        *MfgOffset;
> +  CONST CHAR8  *ManufacturerName;
> +
> +  ContinuationBytes = SpdData[MfgIdCode1Idx] & 0x7F;
> +
> +  if (Ddr5) {
> +    PartNumberLength = DDR_SPD_DDR5_PART_NUMBER_LENGTH + 1;
> +  } else {
> +    PartNumberLength = DDR_SPD_DDR4_PART_NUMBER_LENGTH + 1;
> +  }
> +
> +  Offset = sizeof (SMBIOS_TABLE_TYPE17) +
> +           FixedStringsLength +
> +           (SMBIOS_SERIAL_NUMBER_LENGTH + 1) +
> +           PartNumberLength;
> +
> +  MfgOffset = (CHAR8 *)Type17 + Offset;
> +
> +  ManufacturerName = Jep106GetManufacturerName (
> +                       SpdData[MfgIdCode1Idx + 1],
> +                       ContinuationBytes
> +                       );
> +  if (ManufacturerName != NULL) {
> +    AsciiStrCpyS (MfgOffset, 256, ManufacturerName);
> +  }
> +}
> +
> +/** Parses the serial number from the SPD buffer.
> +
> +  @param SpdData            SPD data buffer.
> +  @param SpdSerialNumberIdx The index of the first byte of the serial number.
> +  @param Type17             SMBIOS Type17 table.
> +  @param FixedStringsLength The length of the fixed strings in the Type 17 table.
> +
> +**/
> +VOID
> +UpdateSerialNumber (
> +  IN UINT8     *SpdData,
> +  IN UINT16    SpdSerialNumberIdx,
> +  IN OUT VOID  *Type17,
> +  IN UINTN     FixedStringsLength
> +  )
> +{
> +  UINTN  FieldIndex;
> +  UINTN  CharIndex;
> +  UINTN  Offset;
> +  CHAR8  *SerialNumber;
> +
> +  Offset = sizeof (SMBIOS_TABLE_TYPE17) +
> +           FixedStringsLength;
> +
> +  SerialNumber = (CHAR8 *)Type17 + Offset;
> +
> +  /*
> +    Calculate a serial number as suggested in JESD400-5:
> +
> +    One method of achieving this is by assigning a byte in the field from
> +    517~520 as a tester ID byte and using the remaining bytes as a sequential
> +    serial number. Bytes 512~520 will then result in a nine-byte unique module
> +    identifier. Note that part number is not included in this identifier: the
> +    supplier may not give the same value for Bytes 517~520 to more than one
> +    DIMM even if the DIMMs have different part numbers.
> +  */
> +
> +  CharIndex = 0;
> +  for (FieldIndex = 0; FieldIndex < DDR_SPD_SERIAL_NUMBER_LENGTH; FieldIndex++) {
> +    UINT8  Temp;
> +    UINT8  Value;
> +
> +    Value = SpdData[SpdSerialNumberIdx + FieldIndex];
> +
> +    Temp = Value >> 4;
> +    if (Temp < 10) {
> +      SerialNumber[CharIndex] = '0' + Temp;
> +    } else {
> +      SerialNumber[CharIndex] = 'A' + (Temp - 10);
> +    }
> +
> +    CharIndex++;
> +    Temp = Value & 0xF;
> +    if (Temp < 10) {
> +      SerialNumber[CharIndex] = '0' + Temp;
> +    } else {
> +      SerialNumber[CharIndex] = 'A' + (Temp - 10);
> +    }
> +
> +    CharIndex++;
> +  }
> +
> +  SerialNumber[CharIndex] = '\0';
> +}
> +
> +/** Parses the part number from the SPD buffer.
> +
> +  @param SpdData             SPD data buffer.
> +  @param PartNumberFieldIdx  Index of the part number field in the SPD data buffer.
> +  @param Type17              SMBIOS Type17 table.
> +  @param FixedStringsLength  Length of the fixed strings in the SMBIOS structure
> +  @param Ddr5                Whether the SPD data buffer is for a DDR5 DIMM.
> +
> +**/
> +VOID
> +UpdatePartNumber (
> +  IN UINT8     *SpdData,
> +  IN UINTN     PartNumberFieldIdx,
> +  IN OUT VOID  *Type17,
> +  IN UINTN     FixedStringsLength,
> +  IN BOOLEAN   Ddr5
> +  )
> +{
> +  UINTN  Offset;
> +  UINTN  PartNumberLength;
> +  CHAR8  *PartNumber;
> +
> +  if (Ddr5) {
> +    PartNumberLength = DDR_SPD_DDR5_PART_NUMBER_LENGTH + 1;
> +  } else {
> +    PartNumberLength = DDR_SPD_DDR4_PART_NUMBER_LENGTH + 1;
> +  }
> +
> +  Offset = sizeof (SMBIOS_TABLE_TYPE17) +
> +           FixedStringsLength +
> +           (SMBIOS_SERIAL_NUMBER_LENGTH + 1);
> +
> +  PartNumber = (CHAR8 *)Type17 + Offset;
> +
> +  // The part number is stored as ASCII, and so can just be copied.
> +  CopyMem (PartNumber, SpdData + PartNumberFieldIdx, PartNumberLength - 1);
> +
> +  PartNumber[PartNumberLength] = '\0';
> +}
> +
> +/**
> +   CRC16 algorithm from JEDEC 4.1.2.L-6 R30 v14
> +
> +   @param Data  Data bytes.
> +   @param Count Number of bytes to calculate the CRC16 over.
> +
> +   @return Calculated CRC16 value.
> +**/
> +UINT16
> +Crc16 (
> +  UINT8  *Data,
> +  INT32  Count
> +  )
> +{
> +  UINT16  Crc;
> +  UINT32  Index;
> +
> +  Crc = 0;
> +  while (--Count >= 0) {
> +    Crc = Crc ^ (UINT16)*Data++ << 8;
> +    for (Index = 0; Index < 8; ++Index) {
> +      if (Crc & 0x8000) {
> +        Crc = Crc << 1 ^ 0x1021;
> +      } else {
> +        Crc = Crc << 1;
> +      }
> +    }
> +  }
> +
> +  return Crc;
> +}
> +
> +/**
> +  Given an SPD data buffer from a DDR4 or DDR5 DIMM, returns a
> +  pointer to a new SMBIOS_TABLE_TYPE17 structure containing data
> +  parsed from the buffer.
> +
> +  @param SpdData             SPD data buffer.
> +  @param SpdDataSize         Size of the SPD data buffer.
> +  @param Type17              SMBIOS Type17 table.
> +  @param FixedStringsLength  Length of the fixed strings in the SMBIOS structure.
> +
> +  @return EFI_SUCCESS on success, or an error code.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetSmbiosType17FromSpdData (
> +  IN     UINT8                *SpdData,
> +  IN     UINTN                SpdDataSize,
> +  OUT    SMBIOS_TABLE_TYPE17  **Type17,
> +  IN UINTN                    FixedStringsLength
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  if (SpdDataSize < (DDR_SPD_PROTOCOL_TYPE_IDX + 1)) {
> +    return EFI_BUFFER_TOO_SMALL;
> +  }
> +
> +  if ((SpdData[DDR_SPD_PROTOCOL_TYPE_IDX] >= SPD_VAL_DDR5_TYPE) &&
> +      (SpdData[DDR_SPD_PROTOCOL_TYPE_IDX] <= SPD_VAL_LPDDR5X_TYPE))
> +  {
> +    Status = ParseDdr5 (SpdData, SpdDataSize, Type17, FixedStringsLength);
> +  } else {
> +    Status = ParseDdr4 (SpdData, SpdDataSize, Type17, FixedStringsLength);
> +  }
> +
> +  return Status;
> +}
> diff --git a/MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SmbiosSpdUnitTest.c b/MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SmbiosSpdUnitTest.c
> new file mode 100644
> index 000000000000..707946f1b3b0
> --- /dev/null
> +++ b/MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SmbiosSpdUnitTest.c
> @@ -0,0 +1,187 @@
> +/** @file
> +  Unit tests for the SMBIOS SPD parsing functions.
> +
> +  Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Uefi.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UnitTestLib.h>
> +#include <IndustryStandard/SmBios.h>
> +#include <Library/SmbiosType17SpdLib.h>
> +
> +#include "SpdTestData.h"
> +
> +#define UNIT_TEST_APP_NAME     "SMBIOS SPD Unit Test Application"
> +#define UNIT_TEST_APP_VERSION  "1.0"
> +
> +typedef struct {
> +  const UINT8                  *TestInput;
> +  UINTN                        TestInputSize;
> +  const SMBIOS_TABLE_TYPE17    *ExpectedResult;
> +  EFI_STATUS                   ExpectedStatus;
> +} SPD_SMBIOS_TEST_CONTEXT;
> +
> +// ------------------------------------------------ Input------------------Input Size----------------------Output------------------Result------
> +static SPD_SMBIOS_TEST_CONTEXT  mSizeTest1 = { Ddr4DimmTestData1, DDR4_SPD_LEN, &Ddr4DimmTestData1ExpectedResult, EFI_SUCCESS };
> +static SPD_SMBIOS_TEST_CONTEXT  mSizeTest2 = { Ddr4DimmTestData2, DDR4_SPD_LEN, &Ddr4DimmTestData2ExpectedResult, EFI_SUCCESS };
> +
> +/**
> + Unit test to verify functionality for DDR4 SPD data.
> +
> + @param Context  Unit test context
> +
> + @return UNIT_TEST_PASSED
> +**/
> +static
> +UNIT_TEST_STATUS
> +EFIAPI
> +SpdCheckTestDdr4 (
> +  IN UNIT_TEST_CONTEXT  Context
> +  )
> +{
> +  EFI_STATUS               Status;
> +  SPD_SMBIOS_TEST_CONTEXT  *TestParams;
> +  SMBIOS_TABLE_TYPE17      *Table;
> +  UINT8                    *SpdData;
> +
> +  TestParams = (SPD_SMBIOS_TEST_CONTEXT *)Context;
> +  Table      = NULL;
> +  SpdData    = (UINT8 *)TestParams->TestInput;
> +
> +  //
> +  // Test case for basic functionality.
> +  //
> +  Status = GetSmbiosType17FromSpdData (SpdData, TestParams->TestInputSize, &Table, 0);
> +  UT_ASSERT_EQUAL (Status, TestParams->ExpectedStatus);
> +  UT_ASSERT_NOT_NULL (Table);
> +
> +  UT_ASSERT_EQUAL (Table->Hdr.Length, sizeof (SMBIOS_TABLE_TYPE17));
> +  UT_ASSERT_EQUAL (Table->TotalWidth, TestParams->ExpectedResult->TotalWidth);
> +  UT_ASSERT_EQUAL (Table->DataWidth, TestParams->ExpectedResult->DataWidth);
> +  UT_ASSERT_EQUAL (Table->Size, TestParams->ExpectedResult->Size);
> +  UT_ASSERT_EQUAL (Table->FormFactor, TestParams->ExpectedResult->FormFactor);
> +  UT_ASSERT_EQUAL (Table->MemoryType, TestParams->ExpectedResult->MemoryType);
> +
> +  // In future, we should calculate the speed bin in the library and verify it here.
> +  //  UT_ASSERT_EQUAL (Table->Speed, TestParams->ExpectedResult->Speed);
> +  //  UT_ASSERT_EQUAL (Table->ConfiguredMemoryClockSpeed, TestParams->ExpectedResult->ConfiguredMemoryClockSpeed);
> +
> +  UT_ASSERT_EQUAL (Table->MinimumVoltage, TestParams->ExpectedResult->MinimumVoltage);
> +  UT_ASSERT_EQUAL (Table->MaximumVoltage, TestParams->ExpectedResult->MaximumVoltage);
> +  UT_ASSERT_EQUAL (Table->ConfiguredVoltage, TestParams->ExpectedResult->ConfiguredVoltage);
> +  UT_ASSERT_EQUAL (Table->MemoryTechnology, TestParams->ExpectedResult->MemoryTechnology);
> +  UT_ASSERT_EQUAL (Table->ModuleManufacturerID, TestParams->ExpectedResult->ModuleManufacturerID);
> +  UT_ASSERT_EQUAL (Table->MemorySubsystemControllerManufacturerID, TestParams->ExpectedResult->MemorySubsystemControllerManufacturerID);
> +  UT_ASSERT_EQUAL (Table->NonVolatileSize, TestParams->ExpectedResult->NonVolatileSize);
> +  UT_ASSERT_EQUAL (Table->VolatileSize, TestParams->ExpectedResult->VolatileSize);
> +  UT_ASSERT_EQUAL (Table->CacheSize, TestParams->ExpectedResult->CacheSize);
> +  UT_ASSERT_EQUAL (Table->LogicalSize, TestParams->ExpectedResult->LogicalSize);
> +  UT_ASSERT_EQUAL (Table->ExtendedSpeed, TestParams->ExpectedResult->ExtendedSpeed);
> +  UT_ASSERT_EQUAL (Table->ExtendedConfiguredMemorySpeed, TestParams->ExpectedResult->ExtendedConfiguredMemorySpeed);
> +
> +  FreePool (Table);
> +
> +  return UNIT_TEST_PASSED;
> +}
> +
> +/**
> +  Initialize the unit test framework, suite, and unit tests for the
> +  SMBIOS SPD APIs of SmbiosType17SpdLib and run the unit tests.
> +
> +  @retval  EFI_SUCCESS           All test cases were dispatched.
> +  @retval  EFI_OUT_OF_RESOURCES  There are not enough resources available to
> +                                 initialize the unit tests.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +UnitTestingEntry (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  UNIT_TEST_FRAMEWORK_HANDLE  Fw;
> +  UNIT_TEST_SUITE_HANDLE      SpdParseTests;
> +
> +  Fw = NULL;
> +
> +  DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION));
> +
> +  //
> +  // Start setting up the test framework for running the tests.
> +  //
> +  Status = InitUnitTestFramework (&Fw, UNIT_TEST_APP_NAME, gEfiCallerBaseName, UNIT_TEST_APP_VERSION);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));
> +    goto EXIT;
> +  }
> +
> +  //
> +  // Populate the SMBIOS SPD Unit Test Suite.
> +  //
> +  Status = CreateUnitTestSuite (&SpdParseTests, Fw, "SMBIOS SPD Parsing Tests", "SpdParseTest", NULL, NULL);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for SpdParseTests\n"));
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto EXIT;
> +  }
> +
> +  // --------------Suite-----------Description-------------------Class Name----------Function-------Pre---Post---Context-----
> +  AddTestCase (SpdParseTests, "SMBIOS SPD Test 1 - DDR4 DIMM", "SmbiosSpd.Test1", SpdCheckTestDdr4, NULL, NULL, &mSizeTest1);
> +  AddTestCase (SpdParseTests, "SMBIOS SPD Test 2 - DDR4 DIMM", "SmbiosSpd.Test2", SpdCheckTestDdr4, NULL, NULL, &mSizeTest2);
> +
> +  //
> +  // Execute the tests.
> +  //
> +  Status = RunAllTestSuites (Fw);
> +
> +EXIT:
> +  if (Fw) {
> +    FreeUnitTestFramework (Fw);
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Standard UEFI entry point for target based unit test execution from UEFI Shell.
> +
> +  @param ImageHandle Image handle.
> +  @param SystemTable System table.
> +
> +  @retval  EFI_SUCCESS           All test cases were dispatched.
> +  @retval  EFI_OUT_OF_RESOURCES  There are not enough resources available to
> +                                 initialize the unit tests.
> +**/
> +EFI_STATUS
> +EFIAPI
> +BaseLibUnitTestAppEntry (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  return UnitTestingEntry ();
> +}
> +
> +/**
> +  Standard POSIX C entry point for host based unit test execution.
> +
> +  @param argc Number of arguments
> +  @param argv Array of arguments
> +
> +  @return 0 on success; non-zero on failure.
> +**/
> +int
> +main (
> +  int   argc,
> +  char  *argv[]
> +  )
> +{
> +  return UnitTestingEntry ();
> +}
> diff --git a/MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SpdTestData.c b/MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SpdTestData.c
> new file mode 100644
> index 000000000000..b0eaff924020
> --- /dev/null
> +++ b/MdePkg/Test/UnitTest/Library/SmbiosType17SpdLib/SpdTestData.c
> @@ -0,0 +1,164 @@
> +/** @file
> +  Arrays defining DDR4 and DDR5 SPD EEPROM data
> +
> +  Copyright (c) Qualcomm Innovation Center, Inc. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <IndustryStandard/SmBios.h>
> +
> +// Data obtained from running systems (with e.g. `hexdump -C /sys/bus/i2c/drivers/ee1004/0-0050/eeprom`)
> +// or from Micron's website.
> +
> +// C code generated from binary files with `xxd -i <inputfile>.bin`
> +
> +/*
> +  https://www.micron.com/products/dram-modules/udimm/part-catalog/mta9asf2g72az-3g2
> +
> +  Micron 16GB PC4-25600 DDR4-3200MHz ECC Unbuffered CL22 UDIMM 1.2V Single-Rank Memory Module
> +*/
> +const UINT8  Ddr4DimmTestData1[] = {
> +  0x23, 0x11, 0x0c, 0x02, 0x86, 0x29, 0x00, 0x08, 0x00, 0x60, 0x00, 0x03,
> +  0x01, 0x0b, 0x80, 0x00, 0x00, 0x00, 0x05, 0x0d, 0xf8, 0xff, 0x2f, 0x00,
> +  0x6e, 0x6e, 0x6e, 0x11, 0x00, 0x6e, 0xf0, 0x0a, 0x20, 0x08, 0x00, 0x05,
> +  0x00, 0xa8, 0x14, 0x28, 0x28, 0x00, 0x78, 0x00, 0x14, 0x3c, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x16, 0x36, 0x16, 0x36, 0x16, 0x36, 0x16, 0x36, 0x16, 0x36, 0x16, 0x36,
> +  0x16, 0x36, 0x16, 0x36, 0x16, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0xa8, 0x14, 0x11, 0x01, 0x43, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x89, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x2c, 0x0f, 0x20,
> +  0x45, 0x2b, 0x38, 0xf2, 0x69, 0x39, 0x41, 0x53, 0x46, 0x32, 0x47, 0x37,
> +  0x32, 0x41, 0x5a, 0x2d, 0x33, 0x47, 0x32, 0x42, 0x31, 0x20, 0x20, 0x20,
> +  0x20, 0x31, 0x80, 0x2c, 0x42, 0x44, 0x50, 0x41, 0x51, 0x38, 0x30, 0x33,
> +  0x30, 0x30, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +};
> +
> +const UINTN Ddr4DimmTestData1Size = sizeof (Ddr4DimmTestData1);
> +
> +const SMBIOS_TABLE_TYPE17  Ddr4DimmTestData1ExpectedResult = {
> +  .TotalWidth                              = 72,
> +  .DataWidth                               = 64,
> +  .Size                                    = (16 * 1024),
> +  .FormFactor                              = MemoryFormFactorDimm,
> +  .MemoryType                              = MemoryTypeDdr4,
> +  .Speed                                   = 3200,
> +  .ConfiguredMemoryClockSpeed              = 3200,
> +  .MinimumVoltage                          = 1200,
> +  .MaximumVoltage                          = 1200,
> +  .ConfiguredVoltage                       = 1200,
> +  .MemoryTechnology                        = MemoryTechnologyDram,
> +  .ModuleManufacturerID                    = 0x2C80,
> +  .MemorySubsystemControllerManufacturerID = 0x2C80,
> +  .NonVolatileSize                         = 0,
> +  .VolatileSize                            = (16ULL * 1024 * 1024 * 1024),
> +  .CacheSize                               = 0,
> +  .LogicalSize                             = (16ULL * 1024 * 1024 * 1024),
> +  .ExtendedSpeed                           = 0,
> +  .ExtendedConfiguredMemorySpeed           = 0
> +};
> +
> +/*
> +  https://www.micron.com/products/dram-modules/vlp-rdimm/part-catalog/mta9adf1g72pz-3g2
> +
> +  Micron MTA9ADF1G72PZ-3G2E1 memory module 8 GB 1x8GB DDR4 3200 MT/s ECC VLP 288-pin RDIMM
> +*/
> +const UINT8  Ddr4DimmTestData2[] = {
> +  0x23, 0x12, 0x0C, 0x01, 0x85, 0x21, 0x00, 0x08, 0x00, 0x60, 0x00, 0x03,
> +  0x01, 0x0B, 0x80, 0x00, 0x00, 0x00, 0x05, 0x0D, 0xF8, 0xFF, 0x2F, 0x00,
> +  0x6E, 0x6E, 0x6E, 0x11, 0x00, 0x6E, 0xF0, 0x0A, 0x20, 0x08, 0x00, 0x05,
> +  0x00, 0xA8, 0x14, 0x28, 0x28, 0x00, 0x78, 0x00, 0x14, 0x3C, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x24, 0x03, 0x15, 0x2C, 0x24, 0x03, 0x15, 0x2C, 0x24, 0x03, 0x24, 0x03,
> +  0x15, 0x2C, 0x24, 0x03, 0x15, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0xE7, 0x00, 0xFF, 0xDF, 0x04, 0x11, 0x06, 0x15,
> +  0x00, 0x86, 0x32, 0xD1, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0xB7, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x2C, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x41, 0x44, 0x46, 0x31, 0x47, 0x37,
> +  0x32, 0x50, 0x5A, 0x2D, 0x33, 0x47, 0x32, 0x45, 0x31, 0x00, 0x00, 0x00,
> +  0x00, 0x31, 0x80, 0x2C, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +};
> +
> +const UINTN Ddr4DimmTestData2Size = sizeof (Ddr4DimmTestData2);
> +
> +const SMBIOS_TABLE_TYPE17  Ddr4DimmTestData2ExpectedResult = {
> +  .TotalWidth                              = 72,
> +  .DataWidth                               = 64,
> +  .Size                                    = (8 * 1024),
> +  .FormFactor                              = MemoryFormFactorDimm,
> +  .MemoryType                              = MemoryTypeDdr4,
> +  .Speed                                   = 3200,
> +  .ConfiguredMemoryClockSpeed              = 3200,
> +  .MinimumVoltage                          = 1200,
> +  .MaximumVoltage                          = 1200,
> +  .ConfiguredVoltage                       = 1200,
> +  .MemoryTechnology                        = MemoryTechnologyDram,
> +  .ModuleManufacturerID                    = 0x2C80,
> +  .MemorySubsystemControllerManufacturerID = 0x2C80,
> +  .NonVolatileSize                         = 0,
> +  .VolatileSize                            = (8ULL * 1024 * 1024 * 1024),
> +  .CacheSize                               = 0,
> +  .LogicalSize                             = (8ULL * 1024 * 1024 * 1024),
> +  .ExtendedSpeed                           = 0,
> +  .ExtendedConfiguredMemorySpeed           = 0
> +};


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#100193): https://edk2.groups.io/g/devel/message/100193
Mute This Topic: https://groups.io/mt/96971232/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list