[edk2-devel] [edk2-platforms][PATCH 4/4] JadePkg: Add support SMBIOS Table Type 16, 17, 19

Minh Nguyen via groups.io posted 4 patches 1 year ago
[edk2-devel] [edk2-platforms][PATCH 4/4] JadePkg: Add support SMBIOS Table Type 16, 17, 19
Posted by Minh Nguyen via groups.io 1 year ago
This adds support SMBIOS Tables Type 16, 17, 19 for information of
Physical Memory, Memory Device and Memory Array Mapped Address.

Signed-off-by: Minh Nguyen <minhnguyen1@os.amperecomputing.com>
---
 Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxe.inf                             |   6 +
 Silicon/Ampere/AmpereAltraPkg/Include/Library/AmpereCpuLib.h                                        |  24 +
 Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxeDataTable.c                      |  26 +-
 Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type16/PlatformPhysicalMemoryArrayData.c          |  48 ++
 Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type16/PlatformPhysicalMemoryArrayFunction.c      |  44 ++
 Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type17/PlatformMemoryDeviceData.c                 |  63 +++
 Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type17/PlatformMemoryDeviceFunction.c             | 475 ++++++++++++++++++++
 Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type19/PlatformMemoryArrayMappedAddressData.c     |  47 ++
 Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type19/PlatformMemoryArrayMappedAddressFunction.c | 150 +++++++
 Silicon/Ampere/AmpereAltraPkg/Library/AmpereCpuLib/AmpereCpuLibCommon.c                             |  42 ++
 Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxeStrings.uni                      |   1 +
 Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type17/PlatformMemoryDevice.uni                   |  16 +
 12 files changed, 941 insertions(+), 1 deletion(-)

diff --git a/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxe.inf b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxe.inf
index 83ff918fc42d..13ae38de01f8 100755
--- a/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxe.inf
+++ b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxe.inf
@@ -25,6 +25,12 @@ [Sources]
   Type09/PlatformSystemSlotFunction.c
   Type11/PlatformOemStringData.c
   Type11/PlatformOemStringFunction.c
+  Type16/PlatformPhysicalMemoryArrayData.c
+  Type16/PlatformPhysicalMemoryArrayFunction.c
+  Type17/PlatformMemoryDeviceData.c
+  Type17/PlatformMemoryDeviceFunction.c
+  Type19/PlatformMemoryArrayMappedAddressData.c
+  Type19/PlatformMemoryArrayMappedAddressFunction.c
   Type24/PlatformHardwareSecurityData.c
   Type24/PlatformHardwareSecurityFunction.c
   Type38/PlatformIpmiDeviceData.c
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/AmpereCpuLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/AmpereCpuLib.h
index c425ed4431da..9b4f2c1e325c 100644
--- a/Silicon/Ampere/AmpereAltraPkg/Include/Library/AmpereCpuLib.h
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/AmpereCpuLib.h
@@ -6,6 +6,8 @@
 
 **/
 
+#include <Guid/PlatformInfoHob.h>
+
 #ifndef AMPERE_CPU_LIB_H_
 #define AMPERE_CPU_LIB_H_
 
@@ -182,6 +184,28 @@ GetScpBuild (
   UINT8 **ScpBuild
   );
 
+/**
+  Get information of DIMM List.
+
+  @param[out]   DimmList   Pointer contains information of DIMM List.
+**/
+VOID
+EFIAPI
+GetDimmList (
+  PLATFORM_DIMM_LIST **DimmList
+  );
+
+/**
+  Get information of DRAM.
+
+  @param[out]   DramInfo   Pointer contains information of DRAM.
+**/
+VOID
+EFIAPI
+GetDramInfo (
+  PLATFORM_DRAM_INFO **DramInfo
+  );
+
 /**
   Set the number of configured CPM per socket.
 
diff --git a/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxeDataTable.c b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxeDataTable.c
index 84a4962d33fc..de5b9b83fb78 100644
--- a/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxeDataTable.c
+++ b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxeDataTable.c
@@ -23,9 +23,21 @@ SMBIOS_PLATFORM_DXE_TABLE_EXTERNS (
   PlatformSystemSlot
   )
 SMBIOS_PLATFORM_DXE_TABLE_EXTERNS (
-  SMBIOS_TABLE_TYPE9,
+  SMBIOS_TABLE_TYPE11,
   PlatformOemString
   )
+SMBIOS_PLATFORM_DXE_TABLE_EXTERNS (
+  SMBIOS_TABLE_TYPE16,
+  PlatformPhysicalMemoryArray
+  )
+SMBIOS_PLATFORM_DXE_TABLE_EXTERNS (
+  SMBIOS_TABLE_TYPE17,
+  PlatformMemoryDevice
+  )
+SMBIOS_PLATFORM_DXE_TABLE_EXTERNS (
+  SMBIOS_TABLE_TYPE19,
+  PlatformMemoryArrayMappedAddress
+  )
 SMBIOS_PLATFORM_DXE_TABLE_EXTERNS (
   SMBIOS_TABLE_TYPE24,
   PlatformHardwareSecurity
@@ -52,6 +64,18 @@ SMBIOS_PLATFORM_DXE_DATA_TABLE mSmbiosPlatformDxeDataTable[] = {
   SMBIOS_PLATFORM_DXE_TABLE_ENTRY_DATA_AND_FUNCTION (
     PlatformOemString
   ),
+  //Type16
+  SMBIOS_PLATFORM_DXE_TABLE_ENTRY_DATA_AND_FUNCTION (
+    PlatformPhysicalMemoryArray
+  ),
+  //Type17
+  SMBIOS_PLATFORM_DXE_TABLE_ENTRY_DATA_AND_FUNCTION (
+    PlatformMemoryDevice
+  ),
+  //Type19
+  SMBIOS_PLATFORM_DXE_TABLE_ENTRY_DATA_AND_FUNCTION (
+    PlatformMemoryArrayMappedAddress
+  ),
   // Type24
   SMBIOS_PLATFORM_DXE_TABLE_ENTRY_DATA_AND_FUNCTION (
     PlatformHardwareSecurity
diff --git a/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type16/PlatformPhysicalMemoryArrayData.c b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type16/PlatformPhysicalMemoryArrayData.c
new file mode 100644
index 000000000000..3c0e6a2ce9a0
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type16/PlatformPhysicalMemoryArrayData.c
@@ -0,0 +1,48 @@
+/** @file
+
+  Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SmbiosPlatformDxe.h"
+
+//
+// Define data for SMBIOS Type 16 Table.
+//
+SMBIOS_PLATFORM_DXE_TABLE_DATA (SMBIOS_TABLE_TYPE16, PlatformPhysicalMemoryArray) = {
+  {                                          // Table 1
+    {                                        // Header
+      EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY, // Type
+      sizeof (SMBIOS_TABLE_TYPE16),          // Length
+      SMBIOS_HANDLE_PI_RESERVED,             // Handle
+    },
+    MemoryArrayLocationSystemBoard,          // Location
+    MemoryArrayUseSystemMemory,              // Use
+    MemoryErrorCorrectionMultiBitEcc,        // Memory Error Correction
+    0x80000000,                              // Maximum Capacity
+    0xFFFE,                                  // Memory Error Information Handle
+    0x10,                                    // Number Of Memory Device
+    0x40000000000ULL                         // Extended Maximum Capacity
+  },
+  {                                          // Null-terminated table
+    {
+      NULL_TERMINATED_TYPE,
+      0,
+      0
+    },
+  }
+};
+
+//
+// Define string Tokens for additional strings.
+//
+SMBIOS_PLATFORM_DXE_STRING_TOKEN_DATA (PlatformPhysicalMemoryArray) = {
+  {                                         // Table 1
+    {                                       // Tokens array
+      NULL_TERMINATED_TOKEN
+    },
+    0                                       // Size of Tokens array
+  }
+};
diff --git a/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type16/PlatformPhysicalMemoryArrayFunction.c b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type16/PlatformPhysicalMemoryArrayFunction.c
new file mode 100644
index 000000000000..772fa02cc256
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type16/PlatformPhysicalMemoryArrayFunction.c
@@ -0,0 +1,44 @@
+/** @file
+
+  Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/AmpereCpuLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#include "SmbiosPlatformDxe.h"
+
+/**
+  This function adds SMBIOS Table (Type 16) records.
+
+  @param  RecordData                 Pointer to SMBIOS Table with default values.
+  @param  Smbios                     SMBIOS protocol.
+
+  @retval EFI_SUCCESS                The SMBIOS Table was successfully added.
+  @retval Other                      Failed to update the SMBIOS Table.
+
+**/
+SMBIOS_PLATFORM_DXE_TABLE_FUNCTION (PlatformPhysicalMemoryArray) {
+  UINT8               Index;
+  EFI_STATUS          Status;
+  SMBIOS_TABLE_TYPE16 *InputData;
+
+  for (Index = 0; Index < GetNumberOfSupportedSockets (); Index++) {
+    InputData = (SMBIOS_TABLE_TYPE16 *)RecordData;
+
+    while (InputData->Hdr.Type != NULL_TERMINATED_TYPE) {
+      Status = SmbiosPlatformDxeAddRecord ((UINT8 *)InputData, NULL);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+
+      InputData++;
+    }
+  }
+
+  return Status;
+}
diff --git a/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type17/PlatformMemoryDeviceData.c b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type17/PlatformMemoryDeviceData.c
new file mode 100644
index 000000000000..2b2c2fc3b4df
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type17/PlatformMemoryDeviceData.c
@@ -0,0 +1,63 @@
+/** @file
+
+  Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SmbiosPlatformDxe.h"
+
+//
+// Define data for SMBIOS Type 17 Table.
+//
+SMBIOS_PLATFORM_DXE_TABLE_DATA (SMBIOS_TABLE_TYPE17, PlatformMemoryDevice) = {
+  {                                   // Table 1
+    {                                 // Hdr
+      EFI_SMBIOS_TYPE_MEMORY_DEVICE,  // Type
+      sizeof (SMBIOS_TABLE_TYPE17),   // Length
+      SMBIOS_HANDLE_PI_RESERVED       // Handle
+    },
+    0xFFFF,                           // Memory Array Handle
+    0xFFFE,                           // Memory Error Information Handle
+    72,                               // Total Width
+    64,                               // Data Width
+    0,                                // Size
+    0x09,                             // Form Factor
+    1,                                // Device Set
+    ADDITIONAL_STR_INDEX_1,           // Device Locator
+    ADDITIONAL_STR_INDEX_2,           // Bank Locator
+    MemoryTypeDdr4,                   // Memory Type
+    {},                               // Type Detail
+    0,                                // Speed
+    ADDITIONAL_STR_INDEX_3,           // Manufacturer
+    ADDITIONAL_STR_INDEX_4,           // Serial
+    ADDITIONAL_STR_INDEX_5,           // Asset Tag
+    ADDITIONAL_STR_INDEX_6,           // Part Number
+    0,                                // Attributes
+  },
+  {                                   // Null-terminated table
+    {
+      NULL_TERMINATED_TYPE,
+      0,
+      0
+    },
+  }
+};
+
+//
+// Define string Tokens for additional strings.
+//
+SMBIOS_PLATFORM_DXE_STRING_TOKEN_DATA (PlatformMemoryDevice) = {
+  {                                                                 // Table 1
+    {                                                               // Tokens array
+      STRING_TOKEN (STR_PLATFORM_DXE_MEMORY_DEVICE_DEVICE_LOCATOR),
+      STRING_TOKEN (STR_PLATFORM_DXE_MEMORY_DEVICE_BANK_LOCATOR),
+      STRING_TOKEN (STR_PLATFORM_DXE_MEMORY_DEVICE_MANUFACTURER),
+      STRING_TOKEN (STR_PLATFORM_DXE_MEMORY_DEVICE_SERIAL_NUMBER),
+      STRING_TOKEN (STR_PLATFORM_DXE_MEMORY_DEVICE_ASSET_TAG),
+      STRING_TOKEN (STR_PLATFORM_DXE_MEMORY_DEVICE_PART_NUMBER)
+    },
+    ADDITIONAL_STR_INDEX_6                                          // Size of Tokens array
+  }
+};
diff --git a/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type17/PlatformMemoryDeviceFunction.c b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type17/PlatformMemoryDeviceFunction.c
new file mode 100644
index 000000000000..d15e4d40a01c
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type17/PlatformMemoryDeviceFunction.c
@@ -0,0 +1,475 @@
+/** @file
+
+  Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Guid/PlatformInfoHob.h>
+#include <Library/AmpereCpuLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+
+#include "SmbiosPlatformDxe.h"
+
+#define NULL_TERMINATED_ID                         0xFF
+
+#define ASCII_SPACE_CHARACTER_CODE                 0x20
+#define ASCII_TILDE_CHARACTER_CODE                 0x7E
+
+#define SPD_PARITY_BIT_MASK                        0x80
+#define SPD_MEMORY_TYPE_OFFSET                     0x02
+#define SPD_CONTINUATION_CHARACTER                 0x7F
+
+#define DDR2_SPD_MANUFACTURER_MEMORY_TYPE          0x08
+#define DDR2_SPD_MANUFACTURER_ID_CODE_LENGTH       8
+#define DDR2_SPD_MANUFACTURER_ID_CODE_OFFSET       64
+#define DDR2_SPD_MANUFACTURER_PART_NUMBER_OFFSET   73
+#define DDR2_SPD_MANUFACTURER_SERIAL_NUMBER_OFFSET 95
+
+#define DDR3_SPD_MANUFACTURER_MEMORY_TYPE          0x0B
+#define DDR3_SPD_MANUFACTURER_ID_BANK_OFFSET       117
+#define DDR3_SPD_MANUFACTURER_ID_CODE_OFFSET       118
+#define DDR3_SPD_MANUFACTURER_PART_NUMBER_OFFSET   128
+#define DDR3_SPD_MANUFACTURER_SERIAL_NUMBER_OFFSET 122
+
+#define DDR4_SPD_MANUFACTURER_MEMORY_TYPE          0x0C
+#define DDR4_SPD_MANUFACTURER_ID_BANK_OFFSET       320
+#define DDR4_SPD_MANUFACTURER_ID_CODE_OFFSET       321
+#define DDR4_SPD_MANUFACTURER_PART_NUMBER_OFFSET   329
+#define DDR4_SPD_MANUFACTURER_SERIAL_NUMBER_OFFSET 325
+
+#define PRINTABLE_CHARACTER(Character) \
+  (Character >= ASCII_SPACE_CHARACTER_CODE) && (Character <= ASCII_TILDE_CHARACTER_CODE) ? \
+  Character : ASCII_SPACE_CHARACTER_CODE
+
+typedef enum {
+  DEVICE_LOCATOR_TOKEN_INDEX = 0,
+  BANK_LOCATOR_TOKEN_INDEX,
+  MANUFACTURER_TOKEN_INDEX,
+  SERIAL_NUMBER_TOKEN_INDEX,
+  ASSET_TAG_TOKEN_INDEX,
+  PART_NUMBER_TOKEN_INDEX
+} MEMORY_DEVICE_TOKEN_INDEX;
+
+#pragma pack(1)
+typedef struct {
+  UINT8  VendorId;
+  CHAR16 *ManufacturerString;
+} JEDEC_MF_ID;
+#pragma pack()
+
+JEDEC_MF_ID Bank0Table[] = {
+  { 0x01, L"AMD\0" },
+  { 0x04, L"Fujitsu\0" },
+  { 0x07, L"Hitachi\0" },
+  { 0x89, L"Intel\0" },
+  { 0x10, L"NEC\0" },
+  { 0x97, L"Texas Instrument\0" },
+  { 0x98, L"Toshiba\0" },
+  { 0x1C, L"Mitsubishi\0" },
+  { 0x1F, L"Atmel\0" },
+  { 0x20, L"STMicroelectronics\0" },
+  { 0xA4, L"IBM\0" },
+  { 0x2C, L"Micron Technology\0" },
+  { 0xAD, L"SK Hynix\0" },
+  { 0xB0, L"Sharp\0" },
+  { 0xB3, L"IDT\0" },
+  { 0x3E, L"Oracle\0" },
+  { 0xBF, L"SST\0" },
+  { 0x40, L"ProMos/Mosel\0" },
+  { 0xC1, L"Infineon\0" },
+  { 0xC2, L"Macronix\0" },
+  { 0x45, L"SanDisk\0" },
+  { 0xCE, L"Samsung\0" },
+  { 0xDA, L"Winbond\0" },
+  { 0xE0, L"LG Semi\0" },
+  { 0x62, L"Sanyo\0" },
+  { NULL_TERMINATED_ID, L"Undefined\0" }
+};
+
+JEDEC_MF_ID Bank1Table[] = {
+  { 0x98, L"Kingston\0" },
+  { 0xBA, L"PNY\0" },
+  { 0x4F, L"Transcend\0" },
+  { 0x7A, L"Apacer\0" },
+  { NULL_TERMINATED_ID, L"Undefined\0" }
+};
+
+JEDEC_MF_ID Bank2Table[] = {
+  { 0x9E, L"Corsair\0" },
+  { 0xFE, L"Elpida\0" },
+  { NULL_TERMINATED_ID, L"Undefined\0" }
+};
+
+JEDEC_MF_ID Bank3Table[] = {
+  { 0x0B, L"Nanya\0" },
+  { 0x94, L"Mushkin\0" },
+  { 0x25, L"Kingmax\0" },
+  { NULL_TERMINATED_ID, L"Undefined\0" }
+};
+
+JEDEC_MF_ID Bank4Table[] = {
+  { 0xB0, L"OCZ\0" },
+  { 0xCB, L"A-DATA\0" },
+  { 0xCD, L"G Skill\0" },
+  { 0xEF, L"Team\0" },
+  { NULL_TERMINATED_ID, L"Undefined\0" }
+};
+
+JEDEC_MF_ID Bank5Table[] = {
+  { 0x02, L"Patriot\0" },
+  { 0x9B, L"Crucial\0" },
+  { 0x51, L"Qimonda\0" },
+  { 0x57, L"AENEON\0" },
+  { 0xF7, L"Avant\0" },
+  { NULL_TERMINATED_ID, L"Undefined\0" }
+};
+
+JEDEC_MF_ID Bank6Table[] = {
+  { 0x34, L"Super Talent\0" },
+  { 0xD3, L"Silicon Power\0" },
+  { NULL_TERMINATED_ID, L"Undefined\0" }
+};
+
+JEDEC_MF_ID Bank7Table[] = {
+  { NULL_TERMINATED_ID, L"Undefined\0" }
+};
+
+JEDEC_MF_ID *ManufacturerJedecIdBankTable[] = {
+  Bank0Table,
+  Bank1Table,
+  Bank2Table,
+  Bank3Table,
+  Bank4Table,
+  Bank5Table,
+  Bank6Table,
+  Bank7Table
+};
+
+VOID
+UpdateManufacturer (
+  IN UINT8  *SpdData,
+  IN UINT16 ManufacturerToken
+  )
+{
+  UINTN       Index;
+  UINT8       VendorId;
+  UINT8       MemType;
+  UINT8       NumberOfJedecIdBankTables;
+  JEDEC_MF_ID *IdTblPtr = NULL;
+
+  MemType = SpdData[SPD_MEMORY_TYPE_OFFSET];
+  switch (MemType) {
+  case DDR2_SPD_MANUFACTURER_MEMORY_TYPE:
+    for (Index = 0; Index < DDR2_SPD_MANUFACTURER_ID_CODE_LENGTH; Index++) {
+      VendorId = SpdData[DDR2_SPD_MANUFACTURER_ID_CODE_OFFSET + Index];
+      if (VendorId != SPD_CONTINUATION_CHARACTER) {
+        break;
+      }
+    }
+    break;
+
+  case DDR3_SPD_MANUFACTURER_MEMORY_TYPE:
+    Index = SpdData[DDR3_SPD_MANUFACTURER_ID_BANK_OFFSET] & (~SPD_PARITY_BIT_MASK); // Remove parity bit
+    VendorId = SpdData[DDR4_SPD_MANUFACTURER_ID_CODE_OFFSET];
+    break;
+
+  case DDR4_SPD_MANUFACTURER_MEMORY_TYPE:
+    Index = SpdData[DDR4_SPD_MANUFACTURER_ID_BANK_OFFSET] & (~SPD_PARITY_BIT_MASK); // Remove parity bit
+    VendorId = SpdData[DDR4_SPD_MANUFACTURER_ID_CODE_OFFSET];
+    break;
+
+  default: // Not supported
+    return;
+  }
+
+  NumberOfJedecIdBankTables = ARRAY_SIZE (ManufacturerJedecIdBankTable) - 1; // Exclude NULL-terminated table
+  if (Index > NumberOfJedecIdBankTables) {
+    Index = NumberOfJedecIdBankTables;
+  }
+  IdTblPtr = ManufacturerJedecIdBankTable[Index];
+
+  // Search in Manufacturer table and update vendor name accordingly in HII Database
+  while (IdTblPtr->VendorId != NULL_TERMINATED_ID) {
+    if (IdTblPtr->VendorId == VendorId) {
+      HiiSetString (mSmbiosPlatformDxeHiiHandle, ManufacturerToken, IdTblPtr->ManufacturerString, NULL);
+      break;
+    }
+    IdTblPtr++;
+  }
+}
+
+VOID
+UpdateSerialNumber (
+  IN UINT8  *SpdData,
+  IN UINT16 SerialNumberToken
+  )
+{
+  UINT8  MemType;
+  UINTN  Offset;
+  CHAR16 SerialNumberStr[SMBIOS_UNICODE_STRING_MAX_LENGTH];
+
+  MemType = SpdData[SPD_MEMORY_TYPE_OFFSET];
+  switch (MemType) {
+  case DDR2_SPD_MANUFACTURER_MEMORY_TYPE:
+    Offset = DDR2_SPD_MANUFACTURER_SERIAL_NUMBER_OFFSET;
+    break;
+
+  case DDR3_SPD_MANUFACTURER_MEMORY_TYPE:
+    Offset = DDR3_SPD_MANUFACTURER_SERIAL_NUMBER_OFFSET;
+    break;
+
+  case DDR4_SPD_MANUFACTURER_MEMORY_TYPE:
+    Offset = DDR4_SPD_MANUFACTURER_SERIAL_NUMBER_OFFSET;
+    break;
+
+  default: // Not supported
+    return;
+  }
+
+  UnicodeSPrint (
+    SerialNumberStr,
+    sizeof (SerialNumberStr),
+    L"%02X%02X%02X%02X",
+    SpdData[Offset],
+    SpdData[Offset + 1],
+    SpdData[Offset + 2],
+    SpdData[Offset + 3]
+    );
+  HiiSetString (mSmbiosPlatformDxeHiiHandle, SerialNumberToken, SerialNumberStr, NULL);
+}
+
+VOID
+UpdatePartNumber (
+  IN UINT8  *SpdData,
+  IN UINT16 PartNumberToken
+  )
+{
+  UINT8  MemType;
+  UINTN  Offset;
+  CHAR16 PartNumberStr[SMBIOS_UNICODE_STRING_MAX_LENGTH];
+
+  MemType = SpdData[SPD_MEMORY_TYPE_OFFSET];
+  switch (MemType) {
+  case DDR2_SPD_MANUFACTURER_MEMORY_TYPE:
+    Offset = DDR2_SPD_MANUFACTURER_PART_NUMBER_OFFSET;
+    break;
+
+  case DDR3_SPD_MANUFACTURER_MEMORY_TYPE:
+    Offset = DDR3_SPD_MANUFACTURER_PART_NUMBER_OFFSET;
+    break;
+
+  case DDR4_SPD_MANUFACTURER_MEMORY_TYPE:
+    Offset = DDR4_SPD_MANUFACTURER_PART_NUMBER_OFFSET;
+    break;
+
+  default: // Not supported
+    return;
+  }
+
+  UnicodeSPrint (
+    PartNumberStr,
+    sizeof (PartNumberStr),
+    L"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+    PRINTABLE_CHARACTER (SpdData[Offset]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 1]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 2]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 3]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 4]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 5]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 6]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 7]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 8]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 9]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 10]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 11]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 12]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 13]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 14]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 15]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 16]),
+    PRINTABLE_CHARACTER (SpdData[Offset + 17])
+    );
+  HiiSetString (mSmbiosPlatformDxeHiiHandle, PartNumberToken, PartNumberStr, NULL);
+}
+
+/**
+  This function adds SMBIOS Table (Type 17) records.
+
+  @param  RecordData                 Pointer to SMBIOS Table with default values.
+  @param  Smbios                     SMBIOS protocol.
+
+  @retval EFI_SUCCESS                The SMBIOS Table was successfully added.
+  @retval Other                      Failed to update the SMBIOS Table.
+
+**/
+SMBIOS_PLATFORM_DXE_TABLE_FUNCTION (PlatformMemoryDevice) {
+  UINT8               Index;
+  UINT8               SlotIndex;
+  UINTN               HandleCount;
+  UINTN               MemorySize;
+  UINT16              *HandleArray;
+  CHAR16              UnicodeStr[SMBIOS_UNICODE_STRING_MAX_LENGTH];
+  EFI_STATUS          Status;
+  SMBIOS_HANDLE       MemoryArrayHandle;
+  PLATFORM_DIMM       *Dimm;
+  STR_TOKEN_INFO      *InputStrToken;
+  PLATFORM_DIMM_LIST  *DimmList;
+  PLATFORM_DRAM_INFO  *DramInfo;
+  SMBIOS_TABLE_TYPE17 *InputData;
+  SMBIOS_TABLE_TYPE17 *Type17Record;
+
+  HandleCount   = 0;
+  HandleArray   = NULL;
+
+  GetDimmList (&DimmList);
+  if (DimmList == NULL) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "[%a]:[%dL] Failed to get Dimm List\n",
+      __func__,
+      __LINE__
+      ));
+    return EFI_NOT_FOUND;
+  }
+
+  GetDramInfo (&DramInfo);
+  if (DramInfo == NULL) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "[%a]:[%dL] Failed to get DRAM Information\n",
+      __func__,
+      __LINE__
+      ));
+    return EFI_NOT_FOUND;
+  }
+
+  SmbiosPlatformDxeGetLinkTypeHandle (
+    EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY,
+    &HandleArray,
+    &HandleCount
+    );
+  if (HandleArray == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  if (HandleCount != GetNumberOfSupportedSockets ()) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "[%a]:[%dL] Failed to get Memory Array Handle\n",
+      __func__,
+      __LINE__
+      ));
+    FreePool (HandleArray);
+    return EFI_NOT_FOUND;
+  }
+
+  for (Index = 0; Index < GetNumberOfSupportedSockets (); Index++) {
+    InputData = (SMBIOS_TABLE_TYPE17 *)RecordData;
+    InputStrToken = (STR_TOKEN_INFO *)StrToken;
+    MemoryArrayHandle = HandleArray[Index];
+
+    while (InputData->Hdr.Type != NULL_TERMINATED_TYPE) {
+      for (SlotIndex = 0; SlotIndex < DimmList->BoardDimmSlots; SlotIndex++) {
+        //
+        // Prepare additional strings for SMBIOS Table.
+        //
+        Dimm = &DimmList->Dimm[SlotIndex];
+        if (Dimm->NodeId != Index) {
+          continue;
+        }
+
+        Status = SmbiosPlatformDxeSaveHiiDefaultString (InputStrToken);
+        if (EFI_ERROR (Status)) {
+          FreePool (HandleArray);
+          return Status;
+        }
+        if (Dimm->Info.DimmStatus == DIMM_INSTALLED_OPERATIONAL) {
+          UpdateManufacturer (Dimm->SpdData.Data, InputStrToken->TokenArray[MANUFACTURER_TOKEN_INDEX]);
+          UpdateSerialNumber (Dimm->SpdData.Data, InputStrToken->TokenArray[SERIAL_NUMBER_TOKEN_INDEX]);
+          UpdatePartNumber (Dimm->SpdData.Data, InputStrToken->TokenArray[PART_NUMBER_TOKEN_INDEX]);
+        }
+        UnicodeSPrint (UnicodeStr, sizeof (UnicodeStr), L"Socket %d DIMM %d", Index, SlotIndex);
+        HiiSetString (mSmbiosPlatformDxeHiiHandle, InputStrToken->TokenArray[DEVICE_LOCATOR_TOKEN_INDEX], UnicodeStr, NULL);
+        UnicodeSPrint (UnicodeStr, sizeof (UnicodeStr), L"Bank %d", SlotIndex);
+        HiiSetString (mSmbiosPlatformDxeHiiHandle, InputStrToken->TokenArray[BANK_LOCATOR_TOKEN_INDEX], UnicodeStr, NULL);
+        UnicodeSPrint (UnicodeStr, sizeof (UnicodeStr), L"Array %d Asset Tag %d", Index, SlotIndex);
+        HiiSetString (mSmbiosPlatformDxeHiiHandle, InputStrToken->TokenArray[ASSET_TAG_TOKEN_INDEX], UnicodeStr, NULL);
+
+        //
+        // Create Table and fill up information.
+        //
+        SmbiosPlatformDxeCreateTable (
+          (VOID *)&Type17Record,
+          (VOID *)&InputData,
+          sizeof (SMBIOS_TABLE_TYPE17),
+          InputStrToken
+          );
+        if (Type17Record == NULL) {
+          FreePool (HandleArray);
+          return EFI_OUT_OF_RESOURCES;
+        }
+
+        if (Dimm->Info.DimmStatus == DIMM_INSTALLED_OPERATIONAL) {
+          MemorySize = Dimm->Info.DimmSize * 1024;
+          if (MemorySize >= 0x7FFF) {
+            Type17Record->Size = 0x7FFF;
+            Type17Record->ExtendedSize = MemorySize;
+          } else {
+            Type17Record->Size = (UINT16)MemorySize;
+            Type17Record->ExtendedSize = 0;
+          }
+
+          Type17Record->MemoryType                 = 0x1A; // DDR4
+          Type17Record->Speed                      = (UINT16)DramInfo->MaxSpeed;
+          Type17Record->ConfiguredMemoryClockSpeed = (UINT16)DramInfo->MaxSpeed;
+          Type17Record->Attributes                 = Dimm->Info.DimmNrRank & 0x0F;
+          Type17Record->ConfiguredVoltage          = 1200;
+          Type17Record->MinimumVoltage             = 1140;
+          Type17Record->MaximumVoltage             = 1260;
+          Type17Record->DeviceSet                  = 0; // None
+
+          if (Dimm->Info.DimmType == UDIMM || Dimm->Info.DimmType == SODIMM) {
+            Type17Record->TypeDetail.Unbuffered = 1; // BIT 14: unregistered
+          } else if (Dimm->Info.DimmType == RDIMM
+                    || Dimm->Info.DimmType == LRDIMM
+                    || Dimm->Info.DimmType == RSODIMM)
+          {
+            Type17Record->TypeDetail.Registered = 1; // BIT 13: registered
+          }
+          /* FIXME: Determine if need to set technology to NVDIMM-* when supported */
+          Type17Record->MemoryTechnology = 0x3; // DRAM
+        }
+        // Update Type 16 handle
+        Type17Record->MemoryArrayHandle = MemoryArrayHandle;
+
+        //
+        // Add Table record and free pool.
+        //
+        Status = SmbiosPlatformDxeAddRecord ((UINT8 *)Type17Record, NULL);
+        if (EFI_ERROR (Status)) {
+          FreePool (HandleArray);
+          FreePool (Type17Record);
+          return Status;
+        }
+
+        FreePool (Type17Record);
+        Status = SmbiosPlatformDxeRestoreHiiDefaultString (InputStrToken);
+        if (EFI_ERROR (Status)) {
+          FreePool (HandleArray);
+          return Status;
+        }
+      }
+
+      InputData++;
+      InputStrToken++;
+    }
+  }
+  FreePool (HandleArray);
+
+  return Status;
+}
diff --git a/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type19/PlatformMemoryArrayMappedAddressData.c b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type19/PlatformMemoryArrayMappedAddressData.c
new file mode 100644
index 000000000000..d14099ae8852
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type19/PlatformMemoryArrayMappedAddressData.c
@@ -0,0 +1,47 @@
+/** @file
+
+  Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SmbiosPlatformDxe.h"
+
+//
+// Define data for SMBIOS Type 19 Table.
+//
+SMBIOS_PLATFORM_DXE_TABLE_DATA (SMBIOS_TABLE_TYPE19, PlatformMemoryArrayMappedAddress) = {
+  {                                                 // Table 1
+    {                                               // Header
+      EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS,  // Type
+      sizeof (SMBIOS_TABLE_TYPE19),                 // Length
+      SMBIOS_HANDLE_PI_RESERVED                     // Handle
+    },
+    0xFFFFFFFF,                                     // Starting Address
+    0xFFFFFFFF,                                     // Ending Address
+    0xFFFF,                                         // Memory Array Handle
+    1,                                              // Partition Width
+    0x0,                                            // Extended Starting Address
+    0x0                                             // Extended Ending Address
+  },
+  {                                                 // Null-terminated table
+    {
+      NULL_TERMINATED_TYPE,
+      0,
+      0
+    },
+  }
+};
+
+//
+// Define string Tokens for additional strings.
+//
+SMBIOS_PLATFORM_DXE_STRING_TOKEN_DATA (PlatformMemoryArrayMappedAddress) = {
+  {                          // Table 1
+    {                        // Tokens array
+      NULL_TERMINATED_TOKEN
+    },
+    0                        // Size of Tokens array
+  }
+};
diff --git a/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type19/PlatformMemoryArrayMappedAddressFunction.c b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type19/PlatformMemoryArrayMappedAddressFunction.c
new file mode 100644
index 000000000000..c57eaef26bf5
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type19/PlatformMemoryArrayMappedAddressFunction.c
@@ -0,0 +1,150 @@
+/** @file
+
+  Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Guid/PlatformInfoHob.h>
+#include <Library/AmpereCpuLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include "SmbiosPlatformDxe.h"
+
+/**
+  This function adds SMBIOS Table (Type 19) records.
+
+  @param  RecordData                 Pointer to SMBIOS Table with default values.
+  @param  Smbios                     SMBIOS protocol.
+
+  @retval EFI_SUCCESS                The SMBIOS Table was successfully added.
+  @retval Other                      Failed to update the SMBIOS Table.
+
+**/
+SMBIOS_PLATFORM_DXE_TABLE_FUNCTION (PlatformMemoryArrayMappedAddress) {
+  UINT8               Index;
+  UINT8               SlotIndex;
+  UINT8               MemRegionIndex;
+  UINTN               HandleCount;
+  UINTN               MemorySize;
+  UINT16              *HandleArray;
+  EFI_STATUS          Status;
+  PLATFORM_DIMM       *Dimm;
+  STR_TOKEN_INFO      *InputStrToken;
+  PLATFORM_DIMM_LIST  *DimmList;
+  PLATFORM_DRAM_INFO  *DramInfo;
+  SMBIOS_TABLE_TYPE19 *InputData;
+  SMBIOS_TABLE_TYPE19 *Type19Record;
+
+  HandleCount   = 0;
+  HandleArray   = NULL;
+
+  GetDimmList (&DimmList);
+  if (DimmList == NULL) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "[%a]:[%dL] Failed to get Dimm List\n",
+      __func__,
+      __LINE__
+      ));
+    return EFI_NOT_FOUND;
+  }
+
+  GetDramInfo (&DramInfo);
+  if (DramInfo == NULL) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "[%a]:[%dL] Failed to get DRAM Information\n",
+      __func__,
+      __LINE__
+      ));
+    return EFI_NOT_FOUND;
+  }
+
+  SmbiosPlatformDxeGetLinkTypeHandle (
+    EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY,
+    &HandleArray,
+    &HandleCount
+    );
+  if (HandleArray == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  if (HandleCount != GetNumberOfSupportedSockets ()) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "[%a]:[%dL] Failed to get Memory Array Handle\n",
+      __func__,
+      __LINE__
+      ));
+    FreePool (HandleArray);
+    return EFI_NOT_FOUND;
+  }
+
+  for (Index = 0; Index < GetNumberOfSupportedSockets (); Index++) {
+    InputData = (SMBIOS_TABLE_TYPE19 *)RecordData;
+    InputStrToken = (STR_TOKEN_INFO *)StrToken;
+    while (InputData->Hdr.Type != NULL_TERMINATED_TYPE) {
+      //
+      // Calculate memory size
+      //
+      for (SlotIndex = 0; SlotIndex < DimmList->BoardDimmSlots; SlotIndex++) {
+        Dimm = &DimmList->Dimm[SlotIndex];
+        if (Dimm->NodeId != Index) {
+          continue;
+        }
+
+        if (Dimm->Info.DimmStatus == DIMM_INSTALLED_OPERATIONAL) {
+          MemorySize = Dimm->Info.DimmSize * 1024;
+        }
+      }
+
+      //
+      // Create Table and fill up information
+      //
+      for (MemRegionIndex = 0; MemRegionIndex < DramInfo->NumRegion; MemRegionIndex++) {
+        SmbiosPlatformDxeCreateTable (
+          (VOID *)&Type19Record,
+          (VOID *)&InputData,
+          sizeof (SMBIOS_TABLE_TYPE19),
+          InputStrToken
+          );
+        if (Type19Record == NULL) {
+          FreePool (HandleArray);
+          return EFI_OUT_OF_RESOURCES;
+        }
+
+        if (DramInfo->NvdRegion[MemRegionIndex] > 0
+            || DramInfo->Socket[MemRegionIndex] != Index)
+        {
+          continue;
+        }
+
+        Type19Record->ExtendedStartingAddress = DramInfo->Base[MemRegionIndex];
+        Type19Record->ExtendedEndingAddress   = DramInfo->Base[MemRegionIndex] +
+                                                DramInfo->Size[MemRegionIndex] -1;
+        if (MemorySize != 0) {
+          Type19Record->PartitionWidth = (DramInfo->Size[MemRegionIndex] - 1) / MemorySize + 1;
+        }
+        Type19Record->MemoryArrayHandle = HandleArray[Index];
+
+        Status = SmbiosPlatformDxeAddRecord ((UINT8 *)Type19Record, NULL);
+        if (EFI_ERROR (Status)) {
+          FreePool (HandleArray);
+          FreePool (Type19Record);
+          return Status;
+        }
+
+        FreePool (Type19Record);
+      }
+
+      InputData++;
+      InputStrToken++;
+    }
+  }
+  FreePool (HandleArray);
+
+  return Status;
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/AmpereCpuLib/AmpereCpuLibCommon.c b/Silicon/Ampere/AmpereAltraPkg/Library/AmpereCpuLib/AmpereCpuLibCommon.c
index 853ab5543f11..0d72853e3d5f 100644
--- a/Silicon/Ampere/AmpereAltraPkg/Library/AmpereCpuLib/AmpereCpuLibCommon.c
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/AmpereCpuLib/AmpereCpuLibCommon.c
@@ -555,6 +555,48 @@ GetScpBuild (
   }
 }
 
+/**
+  Get information of DIMM List.
+
+  @param[out]   DimmList   Pointer contains information of DIMM List.
+**/
+VOID
+EFIAPI
+GetDimmList (
+  PLATFORM_DIMM_LIST **DimmList
+  )
+{
+  PLATFORM_INFO_HOB *PlatformHob;
+
+  PlatformHob = GetPlatformHob ();
+  if (PlatformHob != NULL) {
+    *DimmList = &PlatformHob->DimmList;
+  } else {
+    *DimmList = NULL;
+  }
+}
+
+/**
+  Get information of DRAM.
+
+  @param[out]   DramInfo   Pointer contains information of DRAM.
+**/
+VOID
+EFIAPI
+GetDramInfo (
+  PLATFORM_DRAM_INFO **DramInfo
+  )
+{
+  PLATFORM_INFO_HOB *PlatformHob;
+
+  PlatformHob = GetPlatformHob ();
+  if (PlatformHob != NULL) {
+    *DramInfo = &PlatformHob->DramInfo;
+  } else {
+    *DramInfo = NULL;
+  }
+}
+
 /**
   Set the number of configured CPM per socket.
 
diff --git a/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxeStrings.uni b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxeStrings.uni
index c8176e31ab45..83a76202d614 100644
--- a/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxeStrings.uni
+++ b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxeStrings.uni
@@ -18,4 +18,5 @@
 #include "Type08/PlatformPortConnector.uni"
 #include "Type09/PlatformSystemSlot.uni"
 #include "Type11/PlatformOemString.uni"
+#include "Type17/PlatformMemoryDevice.uni"
 #include "Type41/PlatformOnboardDevicesExtended.uni"
diff --git a/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type17/PlatformMemoryDevice.uni b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type17/PlatformMemoryDevice.uni
new file mode 100644
index 000000000000..012bc241f78a
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Drivers/SmbiosPlatformDxe/Type17/PlatformMemoryDevice.uni
@@ -0,0 +1,16 @@
+/** @file
+
+  Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+/=#
+
+#string STR_PLATFORM_DXE_MEMORY_DEVICE_DEVICE_LOCATOR  #language en-US  "Not set"
+#string STR_PLATFORM_DXE_MEMORY_DEVICE_BANK_LOCATOR    #language en-US  "Not set"
+#string STR_PLATFORM_DXE_MEMORY_DEVICE_MANUFACTURER    #language en-US  "Not set"
+#string STR_PLATFORM_DXE_MEMORY_DEVICE_SERIAL_NUMBER   #language en-US  "Not set"
+#string STR_PLATFORM_DXE_MEMORY_DEVICE_ASSET_TAG       #language en-US  "Not set"
+#string STR_PLATFORM_DXE_MEMORY_DEVICE_PART_NUMBER     #language en-US  "Not set"
-- 
2.39.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#105269): https://edk2.groups.io/g/devel/message/105269
Mute This Topic: https://groups.io/mt/99111900/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-