Browse Source

WhitleyOpenBoardPkg/AcpiTablesLib: Add library for AcpiPlatform driver

AcpiTablesLib allows for board specific updates to ACPI tables.

Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Cc: Chasel Chiu <chasel.chiu@intel.com>
Signed-off-by: Isaac Oram <isaac.w.oram@intel.com>
Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
Isaac Oram 2 years ago
parent
commit
c7bc548d52
19 changed files with 9642 additions and 0 deletions
  1. 534 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLib.c
  2. 127 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLib.inf
  3. 735 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibApic.c
  4. 1574 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibBdat.c
  5. 673 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibDsdt.c
  6. 75 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibFadt.c
  7. 1710 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibHmat.c
  8. 441 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibLocal.h
  9. 134 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMcfg.c
  10. 69 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMigt.c
  11. 101 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMsct.c
  12. 45 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibNfit.c
  13. 42 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibPcat.c
  14. 267 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibPmtt.c
  15. 1153 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSlit.c
  16. 952 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSrat.c
  17. 1004 0
      Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSsdt.c
  18. 5 0
      Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dec
  19. 1 0
      Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dsc

+ 534 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLib.c

@@ -0,0 +1,534 @@
+/** @file
+  ACPI Platform Driver Hooks
+
+  @copyright
+  Copyright 1996 - 2020 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include "AcpiPlatformLibLocal.h"
+#include <Protocol/AcpiSystemDescriptionTable.h>
+#include <Library/UbaPlatLib.h>
+#include <Library/PlatformSpecificAcpiTableLib.h>
+#include <Protocol/DynamicSiLibraryProtocol.h>
+#include <Protocol/DynamicSiLibraryProtocol2.h>
+
+extern BIOS_ACPI_PARAM      *mAcpiParameter;
+
+EFI_PLATFORM_INFO           *mPlatformInfo;
+EFI_CPU_CSR_ACCESS_PROTOCOL *mCpuCsrAccess;
+EFI_ACPI_TABLE_PROTOCOL     *mAcpiTable;
+extern EFI_IIO_UDS_PROTOCOL *mIioUds;
+CPU_CSR_ACCESS_VAR          *mCpuCsrAccessVarPtr;
+
+
+UINT32                      mNumOfBitShift;
+BOOLEAN                     mX2ApicEnabled;
+
+SYSTEM_MEMORY_MAP_HOB      *mSystemMemoryMap;
+
+SOCKET_MEMORY_CONFIGURATION   mSocketMemoryConfiguration;
+SOCKET_MP_LINK_CONFIGURATION  mSocketMpLinkConfiguration;
+SOCKET_IIO_CONFIGURATION      mSocketIioConfiguration;
+SOCKET_POWERMANAGEMENT_CONFIGURATION mSocketPowermanagementConfiguration;
+SOCKET_COMMONRC_CONFIGURATION mSocketCommonRcConfiguration;
+SOCKET_PROCESSORCORE_CONFIGURATION   mSocketProcessorCoreConfiguration;
+
+CPU_CONFIG_CONTEXT_BUFFER *mCpuConfigLibConfigContextBuffer = NULL;
+
+EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE *mSpcrTable = NULL;
+
+/**
+  The constructor function of AcpiPlatormL Library.
+
+  The constructor function caches the value of PCD entry
+
+  @param  ImageHandle   The firmware allocated handle for the EFI image.
+  @param  SystemTable   A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+AcpiPlatformLibConstructor (
+  VOID
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_HOB_GUID_TYPE             *GuidHob;
+
+  DYNAMIC_SI_LIBARY_PROTOCOL  *DynamicSiLibraryProtocol = NULL;
+
+  mCpuConfigLibConfigContextBuffer = (CPU_CONFIG_CONTEXT_BUFFER *) (UINTN) PcdGet64 (PcdCpuConfigContextBuffer);
+  if (mCpuConfigLibConfigContextBuffer == NULL) {
+    ASSERT_EFI_ERROR (RETURN_NOT_FOUND);
+    return RETURN_NOT_FOUND;
+  }
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  GuidHob    = GetFirstGuidHob (&gEfiPlatformInfoGuid);
+  if (GuidHob == NULL) {
+    ASSERT (GuidHob != NULL);
+    return EFI_NOT_FOUND;
+  }
+  mPlatformInfo = GET_GUID_HOB_DATA (GuidHob);
+
+  //
+  // Locate the IIO Protocol Interface
+  //
+  Status = gBS->LocateProtocol (&gEfiIioUdsProtocolGuid,NULL,&mIioUds);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  Status = gBS->LocateProtocol (&gEfiCpuCsrAccessGuid, NULL, &mCpuCsrAccess);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  mCpuCsrAccessVarPtr = DynamicSiLibraryProtocol->GetSysCpuCsrAccessVar ();
+  mSystemMemoryMap = DynamicSiLibraryProtocol->GetSystemMemoryMapData ();
+  ASSERT (mSystemMemoryMap != NULL);
+
+  mMpService = NULL;
+
+  Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, &mMpService);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  //
+  // Determine the number of processors
+  //
+  mMpService->GetNumberOfProcessors (
+    mMpService,
+    &mNumberOfCPUs,
+    &mNumberOfEnabledCPUs
+    );
+  ASSERT (mNumberOfCPUs <= MAX_CPU_NUM && mNumberOfEnabledCPUs >= 1);
+  if (mNumberOfCPUs > MAX_CPU_NUM) {
+    mNumberOfCPUs = MAX_CPU_NUM;
+  }
+
+  Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, &mAcpiTable);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Platform hook to initialize Platform Specific ACPI Parameters
+
+  @retval EFI_SUCCESS            Platform specific parameters in mAcpiParameter
+                                 initialized successfully.
+  @retval EFI_INVALID_PARAMETER  mAcpiParameter global was NULL.
+**/
+EFI_STATUS
+PlatformHookAfterAcpiParamInit (
+  VOID
+  )
+{
+  EFI_STATUS Status;
+
+  Status = EFI_SUCCESS;
+
+  if (mAcpiParameter == NULL) {
+    ASSERT (mAcpiParameter != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((DEBUG_INFO, "ACPI Parameter Block Address: 0x%X\n", mAcpiParameter));
+
+
+  //
+  // Call for Local APIC ID Reorder
+  //
+  Status = SortCpuLocalApicInTable ();
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "[ACPI] ERROR: SortCpuLocalApicInTable failed: %r\n", Status));
+    return Status;
+  }
+
+  return Status;
+}
+
+
+EFI_STATUS
+AcpiPlatformHooksIsActiveTable (
+  IN OUT EFI_ACPI_COMMON_HEADER     *Table
+  )
+{
+  EFI_NFIT_TABLE_UPDATE_PROTOCOL  *NfitTableUpdateProtocol;
+  EFI_ACPI_DESCRIPTION_HEADER     *TableHeader;
+  EFI_STATUS                      Status;
+  SETUP_DATA                      SetupData;
+  SYSTEM_CONFIGURATION            SystemConfiguration;
+  UINT8                           *OemSkuAcpiName;
+
+  Status = GetEntireConfig (&SetupData);
+  ASSERT_EFI_ERROR (Status);
+  CopyMem (&SystemConfiguration, &(SetupData.SystemConfig), sizeof(SYSTEM_CONFIGURATION));
+
+  if (mSystemMemoryMap == NULL) {
+
+    ASSERT (FALSE);
+    return EFI_NOT_FOUND;
+  }
+  TableHeader   = (EFI_ACPI_DESCRIPTION_HEADER *) Table;
+  if (TableHeader->Signature == ACPI_PMTT_TABLE_SIGNATURE) {
+    if (!mSystemMemoryMap->DcpmmPresent) {
+      return EFI_NOT_FOUND;
+    }
+  }
+
+  if (TableHeader->Signature == EFI_BDAT_TABLE_SIGNATURE) {
+    if (mSocketMemoryConfiguration.bdatEn == 0) {
+      return EFI_NOT_FOUND;
+    }
+  }
+
+  if (TableHeader->Signature == NVDIMM_PLATFORM_CONFIG_ATTRIBUTE_TABLE_SIGNATURE) {
+    if (mSystemMemoryMap->DcpmmPresent == 0) {
+        return EFI_NOT_FOUND;
+    }
+  }
+
+  if (TableHeader->Signature == NVDIMM_FW_INTERFACE_TABLE_SIGNATURE) {
+    Status = gBS->LocateProtocol (&gEfiNfitTableUpdateProtocolGuid, NULL, &NfitTableUpdateProtocol);
+    if (EFI_ERROR (Status)){
+      // If NfitTableUpdateProtocol is not found we assume no NVDIMM is present - it means don't publish NFIT
+      DEBUG ((DEBUG_ERROR, "NfitTableUpdateProtocol is not installed.\n"));
+      return EFI_NOT_FOUND;
+    }
+  }
+  if (TableHeader->Signature  ==  EFI_ACPI_6_2_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE) {
+    //
+    // Initialize the SPCR table pointer.
+    // SPCR table is not ready yet, update it before booting.
+    //
+    mSpcrTable = (EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE *) Table;
+    return EFI_NOT_READY;
+  }
+
+  if ((TableHeader->Signature == EFI_ACPI_6_2_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE) ||
+      (TableHeader->Signature == EFI_ACPI_6_2_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE) ||
+      (TableHeader->Signature == EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE) ||
+      TableHeader->Signature == EFI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_SIGNATURE) {
+    //
+    // Only publish SRAT/SLIT/MSCT/HMAT if NUMA is enabled in setup.
+    //
+    if (!mSocketCommonRcConfiguration.NumaEn) {
+
+      DEBUG ((DEBUG_INFO, "[ACPI] NUMA disabled, do not publish '%c%c%c%c' table\n",
+              ((CHAR8*)&TableHeader->Signature)[0], ((CHAR8*)&TableHeader->Signature)[1],
+              ((CHAR8*)&TableHeader->Signature)[2], ((CHAR8*)&TableHeader->Signature)[3]));
+      return EFI_NOT_FOUND;
+    }
+  }
+
+  if (TableHeader->Signature == EFI_ACPI_6_2_DEBUG_PORT_2_TABLE_SIGNATURE) {
+      return EFI_NOT_FOUND;
+  }
+
+  if (TableHeader->Signature == EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
+    OemSkuAcpiName = PcdGetPtr (PcdOemSkuAcpiName);
+    if (OemSkuAcpiName == NULL) {
+      return EFI_UNSUPPORTED;
+    }
+    if ( (0 == CompareMem (&(TableHeader->OemTableId), OemSkuAcpiName, 8)) ) {
+      Status = PlatformGetAcpiFixTableDataPointer (&mAmlOffsetTablePointer);
+      if (!EFI_ERROR(Status)) {
+        DEBUG((DEBUG_INFO, "[ACPI] Platform DSDT Fixup table found\n"));
+        DEBUG((DEBUG_INFO, "[ACPI] Platform SRP: Using %a DSDT\n", OemSkuAcpiName));
+        return EFI_SUCCESS;
+      } else {
+        DEBUG((DEBUG_ERROR, "[ACPI] Platform DSDT Fixup table not found.\n"));
+        return EFI_UNSUPPORTED;
+      }
+    } else {
+      DEBUG ((DEBUG_INFO, "[ACPI] Platform DSDT OemSkuAcpiName '%c%c%c%c%c%c%c%c':\n",
+              ((CHAR8*)OemSkuAcpiName)[0], ((CHAR8*)OemSkuAcpiName)[1],
+              ((CHAR8*)OemSkuAcpiName)[2], ((CHAR8*)OemSkuAcpiName)[3],
+              ((CHAR8*)OemSkuAcpiName)[4], ((CHAR8*)OemSkuAcpiName)[5],
+              ((CHAR8*)OemSkuAcpiName)[6], ((CHAR8*)OemSkuAcpiName)[7]));
+
+      DEBUG ((DEBUG_INFO, " no match for OemTableId '%c%c%c%c%c%c%c%c' from FwVol.\n",
+              ((CHAR8*)&TableHeader->OemTableId)[0], ((CHAR8*)&TableHeader->OemTableId)[1],
+              ((CHAR8*)&TableHeader->OemTableId)[2], ((CHAR8*)&TableHeader->OemTableId)[3],
+              ((CHAR8*)&TableHeader->OemTableId)[4], ((CHAR8*)&TableHeader->OemTableId)[5],
+              ((CHAR8*)&TableHeader->OemTableId)[6], ((CHAR8*)&TableHeader->OemTableId)[7]));
+
+      return EFI_UNSUPPORTED;
+    }
+  }
+
+  //
+  // Hooks for checking additional platform ACPI Table is active or not.
+  // If ACPI Table is not in list, it should be reported and returned EFI_SUCCESS.
+  //
+  return PlatformAcpiReportHooksTableIsActive (Table);
+}
+
+
+/**
+  This function will update any runtime platform specific information.
+  This currently includes:
+    Setting OEM table values, ID, table ID, creator ID and creator revision.
+    Enabling the proper processor entries in the APIC tables.
+
+  @param Table  -  The table to update
+
+  @retval EFI_SUCCESS  -  The function completed successfully.
+**/
+EFI_STATUS
+PlatformUpdateTables (
+  IN OUT EFI_ACPI_COMMON_HEADER     *Table,
+  IN OUT EFI_ACPI_TABLE_VERSION     *Version
+  )
+{
+  EFI_ACPI_DESCRIPTION_HEADER               *TableHeader;
+  EFI_STATUS                                Status;
+  ACPI_APIC_STRUCTURE_PTR                   *ProcessorLocalApicEntry;
+  UINT64                                    TempOemTableId;
+  UINT32                                    Data32;
+
+  DYNAMIC_SI_LIBARY_PROTOCOL2  *DynamicSiLibraryProtocol2 = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  TableHeader             = NULL;
+
+  ProcessorLocalApicEntry = NULL;
+  Status = EFI_SUCCESS;
+
+  //
+  // By default, a table belongs in all ACPI table versions published.
+  // Some tables will override this because they have different versions of the table.
+  //
+  *Version = EFI_ACPI_TABLE_VERSION_2_0;
+
+  if (Table->Signature != EFI_ACPI_6_2_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE &&
+      Table->Signature != EFI_ACPI_6_2_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE &&
+      Table->Signature != SIGNATURE_32('N', 'F', 'I', 'T') &&
+      Table->Signature != SIGNATURE_32('P', 'C', 'A', 'T') &&
+      Table->Signature != SIGNATURE_32('O', 'E', 'M', '1') &&
+      Table->Signature != SIGNATURE_32('O', 'E', 'M', '2') &&
+      Table->Signature != SIGNATURE_32('O', 'E', 'M', '3') &&
+      Table->Signature != SIGNATURE_32('O', 'E', 'M', '4'))
+  {
+    TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table;
+    //
+    // Update the OEMID and OEM Table ID.
+    //
+    TempOemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+
+    CopyMem (TableHeader->OemId, PcdGetPtr(PcdAcpiDefaultOemId), sizeof(TableHeader->OemId));
+    CopyMem (&TableHeader->OemTableId, &TempOemTableId, sizeof(TableHeader->OemTableId));
+
+    //
+    // Update the creator ID
+    //
+    TableHeader->CreatorId = EFI_ACPI_CREATOR_ID;
+
+    //
+    // Update the creator revision
+    //
+    TableHeader->CreatorRevision = EFI_ACPI_CREATOR_REVISION;
+  }
+  //
+  // Complete this function
+  //
+
+  //ASSERT (mMaxNumberOfCPUs <= MAX_CPU_NUM && mNumberOfEnabledCPUs >= 1);
+
+  //
+  // Assign a invalid intial value for update
+  //
+  //
+  // Update the processors in the APIC table
+  //
+  DEBUG ((DEBUG_INFO, "[ACPI] Patching '%c%c%c%c' table...\n",
+          ((CHAR8*)&Table->Signature)[0], ((CHAR8*)&Table->Signature)[1],
+          ((CHAR8*)&Table->Signature)[2], ((CHAR8*)&Table->Signature)[3]));
+  switch (Table->Signature) {
+
+  //
+  // Do not allow a prebuilt MADT, since it is built dynamically.
+  //
+  case EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
+    DEBUG ((DEBUG_ERROR, "[ACPI] ERROR: Prebuilt MADT found\n"));
+    Status = EFI_INVALID_PARAMETER;
+    ASSERT_EFI_ERROR (Status);
+    break;
+
+  case EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
+    Status = PatchFadtTable (Table);
+    break;
+
+  case EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
+    //
+    // Patch the memory resource
+    //
+    Status = PatchDsdtTable (Table);
+    break;
+
+  case EFI_ACPI_6_2_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
+    Status = PatchSsdtTable (Table,Version);
+    break;
+
+  case EFI_ACPI_6_2_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE:
+    //
+    // Adjust HPET Table to correct the Base Address
+    // Get the address bits in RCRB that configure HPET MMIO space
+    //  and create an offset to the pre-defined HEPT base address
+    //
+    DynamicSiLibraryProtocol2->PchHpetBaseGet (&Data32);
+    //
+    // Add the offset to the base address and copy into HPET DSDT table
+    //
+    ((EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *) Table)->BaseAddressLower32Bit.Address = Data32;
+    break;
+
+  case EFI_ACPI_6_2_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE:
+    Status = PatchMcfgAcpiTable (Table);
+    break;
+
+  case EFI_ACPI_6_2_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE:
+    Status = PatchSpcrAcpiTable (Table);
+    break;
+
+  case ACPI_PMTT_TABLE_SIGNATURE:
+    if (!PcdGetBool (PcdPlatformNotSupportAcpiTable)) {
+      Status = PatchPlatformMemoryTopologyTable (Table);
+    }
+    break;
+
+  case EFI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_SIGNATURE:
+    if (!PcdGetBool (PcdPlatformNotSupportAcpiTable)) {
+      Status = PatchHmatAcpiTable (Table);
+    }
+    break;
+
+  case EFI_ACPI_6_2_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE:
+    if (!PcdGetBool (PcdPlatformNotSupportAcpiTable)) {
+      Status = PatchMsctAcpiTable (Table);
+    }
+    break;
+
+  case EFI_MIGT_ACPI_TABLE_SIGNATURE:
+    if (!PcdGetBool (PcdPlatformNotSupportAcpiTable)) {
+      if (PcdGetBool (ReservedB)) {
+        Status = PatchMigtAcpiTable (Table);
+      }
+    }
+    break;
+
+  case EFI_BDAT_TABLE_SIGNATURE:
+    if (!PcdGetBool (PcdPlatformNotSupportAcpiBdatTable)) {
+      Status = PatchBdatAcpiTable (Table);
+    }
+    break;
+
+  case NVDIMM_FW_INTERFACE_TABLE_SIGNATURE:
+    Status = UpdateNfitTable (Table);
+    break;
+
+  case NVDIMM_PLATFORM_CONFIG_ATTRIBUTE_TABLE_SIGNATURE:
+    Status = UpdatePcatTable (Table);
+    break;
+
+  //Patch Dynamic OEM SSDT table
+  case OEM1_SSDT_TABLE_SIGNATURE:
+    Status = PatchOem1SsdtTable (Table);  //CPU EIST
+    break;
+
+  case OEM2_SSDT_TABLE_SIGNATURE:
+    Status = PatchOem2SsdtTable (Table);  //CPU HWP
+    break;
+
+  case OEM3_SSDT_TABLE_SIGNATURE:
+    Status = PatchOem3SsdtTable (Table);  //CPU TST
+    break;
+
+  case OEM4_SSDT_TABLE_SIGNATURE:
+    Status = PatchOem4SsdtTable (Table);  //CPU CST
+    break;
+  case ACPI_WSMT_SIGNATURE:
+    (((ACPI_WINDOWS_SMM_SECURITY_MITIGATIONS_TABLE *)Table)->ProtectionFlags.Flags) = (UINT32 ) (WSMT_PROTECTION_FLAG & PcdGet32(PcdWsmtProtectionFlags));
+  DEBUG ((DEBUG_INFO, "[WSMT] ProtectionFlags = 0x%x\n", (((ACPI_WINDOWS_SMM_SECURITY_MITIGATIONS_TABLE *)Table)->ProtectionFlags.Flags)));
+      break;
+
+  default:
+    //
+    // Hooks for Platform only table. If the ACPI Table is Platform only, add this table in below hook. then continue to update other Table.
+    //
+    Status = PatchPlatformSpecificAcpiTableHooks (Table);
+    break;
+  }
+  //
+  //
+  // Update the hardware signature in the FACS structure
+  //
+  //
+  //
+  return Status;
+}
+
+/**
+  Give the platform a chance to build tables.
+
+  Some tables can be built from scratch more efficiently than being prebuilt
+  and updated. This function builds any such tables for the platform.
+
+  @retval EFI_SUCCESS   Any platform tables were successfully built.
+**/
+EFI_STATUS
+PlatformBuildTables (
+  VOID
+  )
+{
+  EFI_STATUS ReturnStatus = EFI_SUCCESS;
+  EFI_STATUS Status;
+
+  Status = InstallMadtFromScratch ();
+  if (EFI_ERROR (Status)) {
+    ReturnStatus = Status;
+  }
+
+  if (mSocketCommonRcConfiguration.NumaEn) {
+    Status = InstallSlitTable ();
+    if (EFI_ERROR (Status)) {
+      ReturnStatus = Status;
+    }
+
+    Status = InstallSratTable ();
+    if (EFI_ERROR (Status)) {
+      ReturnStatus = Status;
+    }
+  }
+  //
+  // Return the first error code that occured, or success.
+  //
+  return ReturnStatus;
+}

+ 127 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLib.inf

@@ -0,0 +1,127 @@
+## @file
+# Library functions for ACPI Table Update library.
+#
+# @copyright
+# Copyright 2015 - 2020 Intel Corporation. <BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = AcpiPlatformTableLib
+  FILE_GUID                      = 09114814-BF6D-4B2D-BD61-C1F0668DE06E
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = AcpiPlatformTableLib
+  CONSTRUCTOR                    = AcpiPlatformLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = X64
+#
+
+################################################################################
+#
+# Sources Section - list of files that are required for the build to succeed.
+#
+################################################################################
+
+[Sources]
+  AcpiPlatformLibApic.c
+  AcpiPlatformLibBdat.c
+  AcpiPlatformLibDsdt.c
+  AcpiPlatformLibFadt.c
+  AcpiPlatformLibMcfg.c
+  AcpiPlatformLibMsct.c
+  AcpiPlatformLib.c
+  AcpiPlatformLibLocal.h
+  AcpiPlatformLibNfit.c
+  AcpiPlatformLibPcat.c
+  AcpiPlatformLibSlit.c
+  AcpiPlatformLibSrat.c
+  AcpiPlatformLibSsdt.c
+  AcpiPlatformLibMigt.c
+  AcpiPlatformLibPmtt.c
+  AcpiPlatformLibHmat.c
+
+################################################################################
+#
+# Package Dependency Section - list of Package files that are required for
+#                              this module.
+#
+################################################################################
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+  WhitleyOpenBoardPkg/PlatformPkg.dec
+  WhitleySiliconPkg/SiliconPkg.dec
+  WhitleySiliconPkg/CpRcPkg.dec
+  WhitleySiliconPkg/Cpu/CpuRcPkg.dec
+  WhitleySiliconPkg/WhitleySiliconPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  PcdLib
+  MemoryAllocationLib
+  BuildAcpiTablesLib
+  CrcLib
+  UbaPlatLib
+  PlatformSpecificAcpiTableLib
+  CompressDxeLib
+  UefiDecompressLib
+
+[Protocols]
+  gDxePchPlatformPolicyProtocolGuid
+  gEfiNfitTableUpdateProtocolGuid
+  gSmbiosMemInfoProtocolGuid
+  gAcpiPlatformProtocolGuid
+  gEfiSmbiosProtocolGuid
+  gEfiCpuCsrAccessGuid
+  gDynamicSiLibraryProtocolGuid                 ## CONSUMES
+  gDynamicSiLibraryProtocol2Guid                ## CONSUMES
+
+[Guids]
+  gEfiPlatformInfoGuid
+  gFpgaSocketVariableGuid
+  gEwlBdatSchemaGuid
+  gSpdBdatSchemaGuid
+  gSpdVersion1Guid
+  gSpdVariableGuid
+  gMemTrainingDataBdatSchemaGuid
+  gMemTrainingDataVersion1Guid
+  gMemTrainingDataHobGuid
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision
+  gPlatformTokenSpaceGuid.ReservedB
+  gSiPkgTokenSpaceGuid.PcdAcpiBaseAddress
+  gOemSkuTokenSpaceGuid.PcdOemSkuAcpiName
+  gPlatformTokenSpaceGuid.PcdPlatformNotSupportAcpiTable
+  gPlatformTokenSpaceGuid.PcdPlatformNotSupportAcpiBdatTable
+  gPlatformModuleTokenSpaceGuid.PcdWsmtProtectionFlags
+  gPlatformTokenSpaceGuid.PcdHalfWidth
+  gCpuPkgTokenSpaceGuid.PcdCpuConfigContextBuffer       ## CONSUMES
+
+[FixedPcd]
+  gEfiCpRcPkgTokenSpaceGuid.PcdMaxCpuSocketCount
+  gEfiCpRcPkgTokenSpaceGuid.PcdMaxCpuCoreCount
+  gEfiCpRcPkgTokenSpaceGuid.PcdMaxCpuThreadCount
+  gEfiCpRcPkgTokenSpaceGuid.SaveSpdToBdat
+  gEfiCpRcPkgTokenSpaceGuid.SaveMrcTrainingDataToBdat
+
+[Depex]
+  gDynamicSiLibraryProtocolGuid AND
+  gDynamicSiLibraryProtocol2Guid

+ 735 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibApic.c

@@ -0,0 +1,735 @@
+/** @file
+  ACPI Platform Driver Hooks
+
+  @copyright
+  Copyright 1996 - 2020 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include "AcpiPlatformLibLocal.h"
+
+extern EFI_PLATFORM_INFO            *mPlatformInfo;
+extern BIOS_ACPI_PARAM              *mAcpiParameter;
+extern EFI_ACPI_TABLE_PROTOCOL      *mAcpiTable;
+EFI_IIO_UDS_PROTOCOL                *mIioUds = NULL;
+
+extern UINT32                       mNumOfBitShift;
+
+extern BOOLEAN                      mX2ApicEnabled;
+BOOLEAN                             mCpuOrderSorted = FALSE;
+
+extern CPU_CSR_ACCESS_VAR           *mCpuCsrAccessVarPtr;
+EFI_MP_SERVICES_PROTOCOL            *mMpService;
+CPU_ID_ORDER_MAP                    mCpuApicIdOrderTable[MAX_CPU_NUM];
+UINTN                               mNumberOfCPUs = 0;
+UINTN                               mNumberOfEnabledCPUs = 0;
+
+UINT32                              mEnabledProcessor[MAX_SOCKET];
+
+extern UINT32 mCpuPCPSInfo[MAX_SOCKET];
+extern CPU_LOGICAL_THREAD_ID_TABLE  mCpuThreadIdMsrTable[MAX_CPU_NUM];
+
+
+UINT32 mApicIdMap[MAX_SOCKET][MAX_CORE * MAX_THREAD];
+
+UINT32 mThreadCount[MAX_SOCKET] = {0};
+
+typedef struct {
+  UINT64 EnableMask;
+  UINT8  Id;
+  UINT32 GsiBase;
+} IO_APIC_DESCRIPTOR;
+
+STATIC CONST IO_APIC_DESCRIPTOR IoApicDescList[] = {
+  {PCH_IOAPIC,  PCH_IOAPIC_ID,  PCH_INTERRUPT_BASE},
+  {PC00_IOAPIC, PC00_IOAPIC_ID, PC00_INTERRUPT_BASE},
+  {PC01_IOAPIC, PC01_IOAPIC_ID, PC01_INTERRUPT_BASE},
+  {PC02_IOAPIC, PC02_IOAPIC_ID, PC02_INTERRUPT_BASE},
+  {PC03_IOAPIC, PC03_IOAPIC_ID, PC03_INTERRUPT_BASE},
+  {PC04_IOAPIC, PC04_IOAPIC_ID, PC04_INTERRUPT_BASE},
+  {PC05_IOAPIC, PC05_IOAPIC_ID, PC05_INTERRUPT_BASE},
+  {PC06_IOAPIC, PC06_IOAPIC_ID, PC06_INTERRUPT_BASE},
+  {PC07_IOAPIC, PC07_IOAPIC_ID, PC07_INTERRUPT_BASE},
+  {PC08_IOAPIC, PC08_IOAPIC_ID, PC08_INTERRUPT_BASE},
+  {PC09_IOAPIC, PC09_IOAPIC_ID, PC09_INTERRUPT_BASE},
+  {PC10_IOAPIC, PC10_IOAPIC_ID, PC10_INTERRUPT_BASE},
+  {PC11_IOAPIC, PC11_IOAPIC_ID, PC11_INTERRUPT_BASE},
+  {PC12_IOAPIC, PC12_IOAPIC_ID, PC12_INTERRUPT_BASE},
+  {PC13_IOAPIC, PC13_IOAPIC_ID, PC13_INTERRUPT_BASE},
+  {PC14_IOAPIC, PC14_IOAPIC_ID, PC14_INTERRUPT_BASE},
+  {PC15_IOAPIC, PC15_IOAPIC_ID, PC15_INTERRUPT_BASE},
+  {PC16_IOAPIC, PC16_IOAPIC_ID, PC16_INTERRUPT_BASE},
+  {PC17_IOAPIC, PC17_IOAPIC_ID, PC17_INTERRUPT_BASE},
+  {PC18_IOAPIC, PC18_IOAPIC_ID, PC18_INTERRUPT_BASE},
+  {PC19_IOAPIC, PC19_IOAPIC_ID, PC19_INTERRUPT_BASE},
+  {PC20_IOAPIC, PC20_IOAPIC_ID, PC20_INTERRUPT_BASE},
+  {PC21_IOAPIC, PC21_IOAPIC_ID, PC21_INTERRUPT_BASE},
+  {PC22_IOAPIC, PC22_IOAPIC_ID, PC22_INTERRUPT_BASE},
+  {PC23_IOAPIC, PC23_IOAPIC_ID, PC23_INTERRUPT_BASE},
+  {PC24_IOAPIC, PC24_IOAPIC_ID, PC24_INTERRUPT_BASE},
+  {PC25_IOAPIC, PC25_IOAPIC_ID, PC25_INTERRUPT_BASE},
+  {PC26_IOAPIC, PC26_IOAPIC_ID, PC26_INTERRUPT_BASE},
+  {PC27_IOAPIC, PC27_IOAPIC_ID, PC27_INTERRUPT_BASE},
+  {PC28_IOAPIC, PC28_IOAPIC_ID, PC28_INTERRUPT_BASE},
+  {PC29_IOAPIC, PC29_IOAPIC_ID, PC29_INTERRUPT_BASE},
+  {PC30_IOAPIC, PC30_IOAPIC_ID, PC30_INTERRUPT_BASE},
+  {PC31_IOAPIC, PC31_IOAPIC_ID, PC31_INTERRUPT_BASE},
+  {PC32_IOAPIC, PC32_IOAPIC_ID, PC32_INTERRUPT_BASE},
+  {PC33_IOAPIC, PC33_IOAPIC_ID, PC33_INTERRUPT_BASE},
+  {PC34_IOAPIC, PC34_IOAPIC_ID, PC34_INTERRUPT_BASE},
+  {PC35_IOAPIC, PC35_IOAPIC_ID, PC35_INTERRUPT_BASE},
+  {PC36_IOAPIC, PC36_IOAPIC_ID, PC36_INTERRUPT_BASE},
+  {PC37_IOAPIC, PC37_IOAPIC_ID, PC37_INTERRUPT_BASE},
+  {PC38_IOAPIC, PC38_IOAPIC_ID, PC38_INTERRUPT_BASE},
+  {PC39_IOAPIC, PC39_IOAPIC_ID, PC39_INTERRUPT_BASE},
+  {PC40_IOAPIC, PC40_IOAPIC_ID, PC40_INTERRUPT_BASE},
+  {PC41_IOAPIC, PC41_IOAPIC_ID, PC41_INTERRUPT_BASE},
+  {PC42_IOAPIC, PC42_IOAPIC_ID, PC42_INTERRUPT_BASE},
+  {PC43_IOAPIC, PC43_IOAPIC_ID, PC43_INTERRUPT_BASE},
+  {PC44_IOAPIC, PC44_IOAPIC_ID, PC44_INTERRUPT_BASE},
+  {PC45_IOAPIC, PC45_IOAPIC_ID, PC45_INTERRUPT_BASE},
+  {PC46_IOAPIC, PC46_IOAPIC_ID, PC46_INTERRUPT_BASE},
+  {PC47_IOAPIC, PC47_IOAPIC_ID, PC47_INTERRUPT_BASE}
+};
+
+/**
+  Find OrderTable index which is matching input ApicId
+
+  @param ApicId - input ApicId
+
+  @retval Index       - OrderTable index
+  @retval (UINT32) -1 - Not found
+**/
+UINT32
+ApicId2OrderTableIndex (
+  UINT32 ApicId
+  )
+{
+  UINT32 Index;
+
+  for (Index = 0; Index < MAX_CPU_NUM; Index++) {
+    if ((mCpuApicIdOrderTable[Index].Flags == 1) && (mCpuApicIdOrderTable[Index].ApicId == ApicId)) {
+      return Index;
+    }
+  }
+
+  return (UINT32) -1;
+}
+
+/**
+  Display reordered Apic table for detected CPUs.
+
+  @param None
+
+  @retval None
+**/
+VOID
+DebugDisplayReOrderTable (
+  VOID
+  )
+{
+  UINT32 Index;
+  UINT32 TotalEnabledThreads = 0;
+
+  DEBUG ((DEBUG_INFO, "Index  AcpiProcId  ApicId  Flags  Skt\n"));
+  for (Index = 0; Index < MAX_CPU_NUM; Index++) {
+    if (mCpuApicIdOrderTable[Index].ApicId == (UINT32) -1) {
+      break;
+    }
+    TotalEnabledThreads++;
+    DEBUG ((DEBUG_INFO, " %02d       0x%02X      0x%02X      %d      %d\n",
+                           Index, mCpuApicIdOrderTable[Index].AcpiProcessorId,
+                           mCpuApicIdOrderTable[Index].ApicId,
+                           mCpuApicIdOrderTable[Index].Flags,
+                           mCpuApicIdOrderTable[Index].SocketNum));
+  }
+  DEBUG ((DEBUG_INFO, "\n:ACPI: Total Enabled Threads = %d\n\n", TotalEnabledThreads));
+}
+
+/**
+  Consolidate APIC ID order for all populated socket in mApicIdMap table
+
+  @param None
+
+  @retval None
+**/
+VOID
+UpdateApicIdMap (
+  VOID
+  )
+{
+  UINT32 SocketId;
+  UINT32 ThreadIndex;
+  UINT32 CurrProcessor;
+
+  //
+  // init global mApicIdMap variable
+  //
+  SetMem32 ((VOID *)mApicIdMap, sizeof(mApicIdMap), 0xFFFFFFFF);
+
+  for (SocketId = 0; SocketId < MAX_SOCKET; SocketId++) {
+    if ((mCpuCsrAccessVarPtr->socketPresentBitMap & (1 << SocketId)) == 0) {
+      continue;
+    }
+
+    ThreadIndex = 0;
+    for (CurrProcessor = 0; CurrProcessor < MAX_CPU_NUM; CurrProcessor++) {
+      if (mCpuApicIdOrderTable[CurrProcessor].ApicId == (UINT32) -1) {
+        break;
+      }
+
+      if ((mCpuApicIdOrderTable[CurrProcessor].SocketNum == SocketId) && (ThreadIndex < (MAX_CORE * MAX_THREAD))) {
+        mApicIdMap[SocketId][ThreadIndex] = (UINT32) mCpuApicIdOrderTable[CurrProcessor].ApicId & (UINT32) ~(SocketId<< mNumOfBitShift);
+        ThreadIndex++;
+      }
+    }
+
+    if (ThreadIndex != mThreadCount[SocketId]) {
+      DEBUG((DEBUG_ERROR, ":: Skt: %d - Enabled ThreadCount is incorrect!!!\n"));
+      break;
+    }
+  }
+
+  return;
+}
+
+/**
+  Find the processor index of the thread running and obtain MSR 53 and ApicId data
+  to populate mCpuThreadIdMsrTable array.
+
+  @param None
+
+  @retval None
+**/
+VOID
+GetThreadIdMsrValue (
+  VOID
+  )
+{
+  UINTN     ProcessorNumber;
+  UINT64    LogicalIdMsrValue;
+
+  mMpService->WhoAmI (mMpService, &ProcessorNumber);
+  LogicalIdMsrValue = AsmReadMsr64 (0x00000053);
+  mCpuThreadIdMsrTable[ProcessorNumber].ThreadIdValue = (UINT32) LogicalIdMsrValue;
+  mCpuThreadIdMsrTable[ProcessorNumber].CollocatedChaId = (UINT32) RShiftU64(LogicalIdMsrValue, 32);
+  mCpuThreadIdMsrTable[ProcessorNumber].ApicId = mCpuConfigLibConfigContextBuffer->CollectedDataBuffer[ProcessorNumber].CpuMiscData.ApicID;
+}
+
+/**
+  Sort CPU Local APIC Information.
+
+  This function gets the CPU local APIC information from the MP service
+  protocol into the local table structure, and sorts it based on APIC ID.
+
+  @retval EFI_SUCCESS   Local APIC information was successfully sorted.
+**/
+EFI_STATUS
+SortCpuLocalApicInTable (
+  VOID
+  )
+{
+  EFI_STATUS                                Status;
+  EFI_PROCESSOR_INFORMATION                 ProcessorInfoBuffer;
+  UINTN                                     BufferSize;
+  UINT32                                    Index;
+  UINT32                                    Socket;
+  UINT32                                    CurrProcessor;
+  CPU_ID_ORDER_MAP                          *CpuIdMapPtr;
+  UINT32                                    CoreThreadMask;
+  UINT32                                    CoreThreadCount;
+  UINT32                                    BspApicId;
+  UINT32                                    LowestApicId;
+  UINT32                                    CurrentIndex;
+  UINT32                                    TargetIndex;
+  CPU_ID_ORDER_MAP                          TempEntry;
+  BOOLEAN                                   SecondThreadExistent;
+
+  BufferSize = 0;
+  Index      = 0;
+  Status     = EFI_SUCCESS;
+
+  CoreThreadMask = (UINT32) ((1 << mNumOfBitShift) - 1);
+  CoreThreadCount = 0;
+
+  if (!mCpuOrderSorted) {
+    //
+    // Init ProcessorBitMask table and EnabledProcessor table
+    //
+    for (Index = 0; Index < MAX_SOCKET; Index++) {
+      mAcpiParameter->ProcessorBitMask[Index] = 0;
+      mAcpiParameter->ProcessorBitMaskHi[Index] = 0;
+      mEnabledProcessor[Index] = 0;
+      mCpuPCPSInfo[Index] = 0;
+    }
+
+    Index  = 0;
+    SecondThreadExistent = FALSE;
+    for (CurrProcessor = 0; CurrProcessor < mNumberOfCPUs; CurrProcessor++) {
+      Status = mMpService->GetProcessorInfo (
+        mMpService,
+        CurrProcessor,
+        &ProcessorInfoBuffer
+        );
+      ASSERT_EFI_ERROR (Status);
+      if (EFI_ERROR (Status)) {
+        continue;
+      }
+
+
+      if (ProcessorInfoBuffer.ProcessorId & 1) {  // secondary thread
+        CpuIdMapPtr = &mCpuApicIdOrderTable[(Index - 1) + MAX_CPU_NUM / 2];
+        SecondThreadExistent= TRUE;
+      } else {                                    // primary thread
+        CpuIdMapPtr = &mCpuApicIdOrderTable[Index];
+        Index++;
+      }
+
+      CpuIdMapPtr->ApicId  = (UINT32) ProcessorInfoBuffer.ProcessorId;
+      CpuIdMapPtr->Flags   = ((ProcessorInfoBuffer.StatusFlag & PROCESSOR_ENABLED_BIT) != 0);
+      CpuIdMapPtr->SocketNum = (UINT32) ProcessorInfoBuffer.Location.Package;
+      CpuIdMapPtr->AcpiProcessorId = (CpuIdMapPtr->SocketNum << mNumOfBitShift) + mThreadCount[CpuIdMapPtr->SocketNum];
+
+      mThreadCount[CpuIdMapPtr->SocketNum]++;
+
+      if (CpuIdMapPtr->Flags == 1) {
+        //
+        // Update EnabledProcessor table
+        //
+        mEnabledProcessor[CpuIdMapPtr->SocketNum]++;
+        mCpuPCPSInfo[CpuIdMapPtr->SocketNum]++; // count enabled processor in current socket
+
+        //
+        // Update processorbitMask
+        //
+        if (ProcessorInfoBuffer.Location.Core < 64) {
+          mAcpiParameter->ProcessorBitMask[CpuIdMapPtr->SocketNum] |=
+            LShiftU64 (1, ProcessorInfoBuffer.Location.Core);
+        } else {
+          mAcpiParameter->ProcessorBitMaskHi[CpuIdMapPtr->SocketNum] |=
+            LShiftU64 (1, ProcessorInfoBuffer.Location.Core - 64);
+        }
+
+        if (ProcessorInfoBuffer.Location.Thread >= CoreThreadCount) {
+          CoreThreadCount = ProcessorInfoBuffer.Location.Thread + 1;
+        }
+      }
+    } //end for CurrentProcessor
+
+    DEBUG ((
+      DEBUG_INFO,
+      "::ACPI::  APIC ID Order Table Init.   CoreThreadMask = 0x%x,   mNumOfBitShift = %d,   CoreThreadCount = %d\n",
+      CoreThreadMask,
+      mNumOfBitShift,
+      CoreThreadCount
+      ));
+
+    DEBUG ((DEBUG_INFO, "::ACPI::  Socket  ProcessorBitMaskHi ProcessorBitMask   ProcessorApicIdBase\n"));
+    for (Index = 0; Index < MAX_SOCKET; Index++) {
+      DEBUG ((
+        DEBUG_INFO,
+        "::ACPI::    %d     0x%016lx %016lx          0x%x\n",
+        Index,
+        mAcpiParameter->ProcessorBitMaskHi[Index],
+        mAcpiParameter->ProcessorBitMask[Index],
+        mAcpiParameter->ProcessorApicIdBase[Index]
+        ));
+    }
+    AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 1, NULL, NULL, NULL, &BspApicId);
+
+    if (mCpuApicIdOrderTable[0].ApicId != BspApicId) {
+      //
+      // check to see if 1st entry is BSP, if not swap it
+      //
+      CurrentIndex = ApicId2OrderTableIndex (BspApicId);
+
+      if (CurrentIndex >= MAX_CPU_NUM) {
+        DEBUG ((DEBUG_ERROR, "BSP index is out of range\n"));
+        ASSERT (CurrentIndex < MAX_CPU_NUM);
+      } else {
+        LowestApicId = mCpuApicIdOrderTable[0].ApicId;
+        TargetIndex = 0;
+        CopyMem (&TempEntry, &mCpuApicIdOrderTable[CurrentIndex], sizeof(TempEntry));
+        CopyMem (&mCpuApicIdOrderTable[CurrentIndex], &mCpuApicIdOrderTable[TargetIndex], sizeof(TempEntry));
+        CopyMem (&mCpuApicIdOrderTable[TargetIndex], &TempEntry, sizeof(TempEntry));
+
+        if (SecondThreadExistent) {
+          //
+          // Also swap BSP's companion thread (the second thread in same core of BSP)
+          //
+          CurrentIndex = ApicId2OrderTableIndex (BspApicId + 1);
+          TargetIndex = ApicId2OrderTableIndex (LowestApicId + 1);
+          if ((CurrentIndex < MAX_CPU_NUM) && (TargetIndex < MAX_CPU_NUM)) {
+            CopyMem (&TempEntry, &mCpuApicIdOrderTable[CurrentIndex], sizeof(TempEntry));
+            CopyMem (&mCpuApicIdOrderTable[CurrentIndex], &mCpuApicIdOrderTable[TargetIndex], sizeof(TempEntry));
+            CopyMem (&mCpuApicIdOrderTable[TargetIndex], &TempEntry, sizeof(TempEntry));
+          }
+        }
+      }
+    }
+
+    //
+    // Make sure no holes between enabled threads
+    //
+    for (CurrProcessor = 0; CurrProcessor < MAX_CPU_NUM; CurrProcessor++) {
+
+      if (mCpuApicIdOrderTable[CurrProcessor].Flags == 0) {
+        //
+        // make sure disabled entry has ProcId set to FFs
+        //
+        mCpuApicIdOrderTable[CurrProcessor].ApicId = (UINT32) -1;
+        mCpuApicIdOrderTable[CurrProcessor].AcpiProcessorId = (UINT32) -1;
+
+        for (Index = CurrProcessor + 1; Index < MAX_CPU_NUM; Index++) {
+          if (mCpuApicIdOrderTable[Index].Flags == 1) {
+            //
+            // move enabled entry up
+            //
+            mCpuApicIdOrderTable[CurrProcessor].Flags = 1;
+            mCpuApicIdOrderTable[CurrProcessor].ApicId = mCpuApicIdOrderTable[Index].ApicId;
+            mCpuApicIdOrderTable[CurrProcessor].AcpiProcessorId = mCpuApicIdOrderTable[Index].AcpiProcessorId;
+            mCpuApicIdOrderTable[CurrProcessor].SocketNum = mCpuApicIdOrderTable[Index].SocketNum;
+            //
+            // disable moved entry
+            //
+            mCpuApicIdOrderTable[Index].Flags = 0;
+            mCpuApicIdOrderTable[Index].ApicId = (UINT32) -1;
+            mCpuApicIdOrderTable[Index].AcpiProcessorId = (UINT32) -1;
+            break;
+          }
+        }
+      }
+    }
+
+    //
+    // keep for debug purpose
+    //
+    DEBUG ((DEBUG_INFO, "APIC ID Order Table ReOrdered\n"));
+    DebugDisplayReOrderTable ();
+
+    //
+    // Re-sort AcpiProcessorId for all sockets
+    //
+    for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+      Index  = 0;
+
+      for (CurrProcessor = 0; CurrProcessor < MAX_CPU_NUM; CurrProcessor++) {
+        if (mCpuApicIdOrderTable[CurrProcessor].Flags && (mCpuApicIdOrderTable[CurrProcessor].SocketNum == Socket)) {
+          //
+          // re-assign AcpiProcessorId to match MADT (socket, thread)
+          //
+          mCpuApicIdOrderTable[CurrProcessor].AcpiProcessorId = (Socket << mNumOfBitShift) + Index;
+          Index++;
+        }
+      }
+    }
+
+    //
+    // keep for debug purpose
+    //
+    DEBUG ((DEBUG_INFO, "APIC ID Ord Tbl ReOrd aft Re-sort AcpiProcessorId\n"));
+    DebugDisplayReOrderTable ();
+
+    //
+    // Update mApicIdMap according the final mCpuApicIdOrderTable
+    //
+    UpdateApicIdMap ();
+
+    for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+    for (Index=0; Index < (MAX_THREAD * MAX_CORE); Index++) {
+        if (mApicIdMap[Socket][Index] != (UINT32) -1) {
+          DEBUG ((DEBUG_INFO, "mApicIdMap[%d][%d] = 0x%x\n", Socket, Index, mApicIdMap[Socket][Index]));
+        }
+      }
+    }
+
+    //
+    // Initialize with safe defaults
+    //
+    for(CurrProcessor = 0; CurrProcessor < MAX_CPU_NUM; CurrProcessor++) {
+      mCpuThreadIdMsrTable[CurrProcessor].ApicId = (UINT32)-1;
+      mCpuThreadIdMsrTable[CurrProcessor].ThreadIdValue = 0xFF;
+      mCpuThreadIdMsrTable[CurrProcessor].CollocatedChaId = 0xFF;
+      mCpuThreadIdMsrTable[CurrProcessor].SNCProximityDomain = 0;
+    }
+    //
+    // Collect MSR 53 value and ApicId for each thread
+    //
+    mMpService->StartupAllAPs (mMpService, (EFI_AP_PROCEDURE)GetThreadIdMsrValue, FALSE, NULL, 0, NULL, NULL);
+    GetThreadIdMsrValue ();
+
+    mCpuOrderSorted = TRUE;
+  }
+
+  return Status;
+}
+
+/**
+  Build from scratch and install the MADT.
+
+  @retval EFI_SUCCESS           The MADT was installed successfully.
+  @retval EFI_OUT_OF_RESOURCES  Could not allocate required structures.
+**/
+EFI_STATUS
+InstallMadtFromScratch (
+  VOID
+  )
+{
+  EFI_STATUS                                          Status;
+  UINTN                                               Index;
+  EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *NewMadtTable;
+  UINTN                                               TableHandle;
+  EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER MadtTableHeader;
+  EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_STRUCTURE         ProcLocalApicStruct;
+  EFI_ACPI_6_2_IO_APIC_STRUCTURE                      IoApicStruct;
+  EFI_ACPI_6_2_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE    IntSrcOverrideStruct;
+  EFI_ACPI_6_2_LOCAL_APIC_NMI_STRUCTURE               LocalApciNmiStruct;
+  EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_STRUCTURE       ProcLocalX2ApicStruct;
+  EFI_ACPI_6_2_LOCAL_X2APIC_NMI_STRUCTURE             LocalX2ApicNmiStruct;
+  STRUCTURE_HEADER                                    **MadtStructs;
+  UINTN                                               MaxMadtStructCount;
+  UINTN                                               MadtStructsIndex;
+
+  NewMadtTable = NULL;
+
+  MaxMadtStructCount = (UINT32) (
+    MAX_CPU_NUM +         // processor local APIC structures
+    MAX_CPU_NUM +         // processor local x2APIC structures
+    MAX_IO_APICS_10NM +   // IOAPIC structures
+    2 +                   // interrupt source override structures
+    1 +                   // local APIC NMI structures
+    1                     // local x2APIC NMI structures
+  );                      // other structures are not used
+
+  MadtStructs = (STRUCTURE_HEADER **) AllocateZeroPool (MaxMadtStructCount * sizeof (STRUCTURE_HEADER *));
+  if (MadtStructs == NULL) {
+    DEBUG ((DEBUG_ERROR, "[ACPI](MADT) Could not allocate MADT structure pointer array\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Initialize the next index into the structure pointer array. It is
+  // incremented every time a structure of any type is copied to the array.
+  //
+  MadtStructsIndex = 0;
+
+  //
+  // Initialize MADT Header Structure
+  //
+  Status = InitializeMadtHeader (&MadtTableHeader);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "[ACPI](MADT) InitializeMadtHeader failed: %r\n", Status));
+    goto Done;
+  }
+
+  DEBUG ((DEBUG_INFO, "[ACPI](MADT) Number of CPUs detected = %d \n", mNumberOfCPUs));
+
+  //
+  // Build Processor Local APIC Structures and Processor Local X2APIC Structures
+  //
+  ProcLocalApicStruct.Type = EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC;
+  ProcLocalApicStruct.Length = sizeof (EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_STRUCTURE);
+
+  ProcLocalX2ApicStruct.Type = EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC;
+  ProcLocalX2ApicStruct.Length = sizeof (EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_STRUCTURE);
+  ProcLocalX2ApicStruct.Reserved[0] = 0;
+  ProcLocalX2ApicStruct.Reserved[1] = 0;
+
+  for (Index = 0; Index < mNumberOfCPUs; Index++) {
+    //
+    // If x2APIC mode is not enabled, and if it is possible to express the
+    // APIC ID as a UINT8, use a processor local APIC structure. Otherwise,
+    // use a processor local x2APIC structure.
+    //
+    if (!mX2ApicEnabled && mCpuApicIdOrderTable[Index].ApicId < MAX_UINT8) {
+      ProcLocalApicStruct.Flags           = (UINT8) mCpuApicIdOrderTable[Index].Flags;
+      ProcLocalApicStruct.ApicId          = (UINT8) mCpuApicIdOrderTable[Index].ApicId;
+      ProcLocalApicStruct.AcpiProcessorUid = (UINT8) mCpuApicIdOrderTable[Index].AcpiProcessorId;
+
+      ASSERT (MadtStructsIndex < MaxMadtStructCount);
+      Status = CopyStructure (
+        &MadtTableHeader.Header,
+        (STRUCTURE_HEADER *) &ProcLocalApicStruct,
+        &MadtStructs[MadtStructsIndex++]
+        );
+    } else {
+      ProcLocalX2ApicStruct.Flags            = (UINT8) mCpuApicIdOrderTable[Index].Flags;
+      ProcLocalX2ApicStruct.X2ApicId         = mCpuApicIdOrderTable[Index].ApicId;
+      ProcLocalX2ApicStruct.AcpiProcessorUid = mCpuApicIdOrderTable[Index].AcpiProcessorId;
+
+      ASSERT (MadtStructsIndex < MaxMadtStructCount);
+      Status = CopyStructure (
+        &MadtTableHeader.Header,
+        (STRUCTURE_HEADER *) &ProcLocalX2ApicStruct,
+        &MadtStructs[MadtStructsIndex++]
+        );
+    }
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "[ACPI](MADT) CopyMadtStructure (local APIC/x2APIC) failed: %r\n", Status));
+      goto Done;
+    }
+  }
+
+  //
+  // Build IOAPIC Structures
+  //
+  if (mIioUds == NULL) {
+    Status = gBS->LocateProtocol (&gEfiIioUdsProtocolGuid,NULL,&mIioUds);
+    ASSERT_EFI_ERROR (Status);
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+  }
+
+  IoApicStruct.Type = EFI_ACPI_6_2_IO_APIC;
+  IoApicStruct.Length = sizeof (EFI_ACPI_6_2_IO_APIC_STRUCTURE);
+  IoApicStruct.Reserved = 0;
+  IoApicStruct.IoApicId = PCH_IOAPIC_ID;
+  IoApicStruct.IoApicAddress =  mIioUds->IioUdsPtr->PlatformData.IIO_resource[0].StackRes[0].IoApicBase;
+  IoApicStruct.GlobalSystemInterruptBase = PCH_INTERRUPT_BASE;
+  ASSERT (MadtStructsIndex < MaxMadtStructCount);
+  Status = CopyStructure (
+    &MadtTableHeader.Header,
+    (STRUCTURE_HEADER *) &IoApicStruct,
+    &MadtStructs[MadtStructsIndex++]
+    );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "[ACPI](MADT) CopyMadtStructure (IOAPIC) failed: %r\n", Status));
+    goto Done;
+  }
+  DEBUG ((DEBUG_INFO, "[ACPI](MADT) Add IOAPIC id %d, addr 0x%x, Interrupt base %d for PCH\n", IoApicStruct.IoApicId, IoApicStruct.IoApicAddress, IoApicStruct.GlobalSystemInterruptBase));
+
+  //
+  // Build Interrupt Source Override Structures
+  //
+  IntSrcOverrideStruct.Type = EFI_ACPI_6_2_INTERRUPT_SOURCE_OVERRIDE;
+  IntSrcOverrideStruct.Length = sizeof (EFI_ACPI_6_2_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE);
+
+  //
+  // IRQ0=>IRQ2 Interrupt Source Override Structure
+  //
+  IntSrcOverrideStruct.Bus = 0x0;                   // Bus - ISA
+  IntSrcOverrideStruct.Source = 0x0;                // Source - IRQ0
+  IntSrcOverrideStruct.GlobalSystemInterrupt = 0x2; // Global System Interrupt - IRQ2
+  IntSrcOverrideStruct.Flags = 0x0;                 // Flags - Conforms to specifications of the bus
+
+  ASSERT (MadtStructsIndex < MaxMadtStructCount);
+  Status = CopyStructure (
+    &MadtTableHeader.Header,
+    (STRUCTURE_HEADER *) &IntSrcOverrideStruct,
+    &MadtStructs[MadtStructsIndex++]
+    );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "[ACPI](MADT) CopyMadtStructure (IRQ2 source override) failed: %r\n", Status));
+    goto Done;
+  }
+
+  //
+  // IRQ9 (SCI Active High) Interrupt Source Override Structure
+  //
+  IntSrcOverrideStruct.Bus = 0x0;                   // Bus - ISA
+  IntSrcOverrideStruct.Source = 0x9;                // Source - IRQ9
+  IntSrcOverrideStruct.GlobalSystemInterrupt = 0x9; // Global System Interrupt - IRQ9
+  IntSrcOverrideStruct.Flags = 0xD;                 // Flags - Level-tiggered, Active High
+
+  ASSERT (MadtStructsIndex < MaxMadtStructCount);
+  Status = CopyStructure (
+    &MadtTableHeader.Header,
+    (STRUCTURE_HEADER *) &IntSrcOverrideStruct,
+    &MadtStructs[MadtStructsIndex++]
+    );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "[ACPI](MADT) CopyMadtStructure (IRQ9 source override) failed: %r\n", Status));
+    goto Done;
+  }
+
+  //
+  // Build Local APIC NMI Structures
+  //
+  LocalApciNmiStruct.Type   = EFI_ACPI_6_2_LOCAL_APIC_NMI;
+  LocalApciNmiStruct.Length = sizeof (EFI_ACPI_6_2_LOCAL_APIC_NMI_STRUCTURE);
+  LocalApciNmiStruct.AcpiProcessorUid = 0xFF;      // Applies to all processors
+  LocalApciNmiStruct.Flags  = POLARITY_ACTIVE_HIGH | TRIGGERMODE_EDGE; // Flags - Edge-tiggered, Active High
+  LocalApciNmiStruct.LocalApicLint   = 0x1;
+
+  ASSERT (MadtStructsIndex < MaxMadtStructCount);
+  Status = CopyStructure (
+    &MadtTableHeader.Header,
+    (STRUCTURE_HEADER *) &LocalApciNmiStruct,
+    &MadtStructs[MadtStructsIndex++]
+    );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "[ACPI](MADT) CopyMadtStructure (APIC NMI) failed: %r\n", Status));
+    goto Done;
+  }
+
+  //
+  // Build Local x2APIC NMI Structure
+  //
+  LocalX2ApicNmiStruct.Type   = EFI_ACPI_6_2_LOCAL_X2APIC_NMI;
+  LocalX2ApicNmiStruct.Length = sizeof (EFI_ACPI_6_2_LOCAL_X2APIC_NMI_STRUCTURE);
+  LocalX2ApicNmiStruct.Flags  = POLARITY_ACTIVE_HIGH | TRIGGERMODE_EDGE; // Flags - Edge-tiggered, Active High
+  LocalX2ApicNmiStruct.AcpiProcessorUid = 0xFFFFFFFF;  // Applies to all processors
+  LocalX2ApicNmiStruct.LocalX2ApicLint  = 0x01;
+  LocalX2ApicNmiStruct.Reserved[0] = 0x00;
+  LocalX2ApicNmiStruct.Reserved[1] = 0x00;
+  LocalX2ApicNmiStruct.Reserved[2] = 0x00;
+
+  ASSERT (MadtStructsIndex < MaxMadtStructCount);
+  Status = CopyStructure (
+    &MadtTableHeader.Header,
+    (STRUCTURE_HEADER *) &LocalX2ApicNmiStruct,
+    &MadtStructs[MadtStructsIndex++]
+    );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "[ACPI](MADT) CopyMadtStructure (x2APIC NMI) failed: %r\n", Status));
+    goto Done;
+  }
+
+  //
+  // Build Madt Structure from the Madt Header and collection of pointers in MadtStructs[]
+  //
+  Status = BuildAcpiTable (
+    (EFI_ACPI_DESCRIPTION_HEADER *) &MadtTableHeader,
+    sizeof (EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER),
+    MadtStructs,
+    MadtStructsIndex,
+    (UINT8 **)&NewMadtTable
+    );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "[ACPI](MADT) BuildAcpiTable failed: %r\n", Status));
+    goto Done;
+  }
+
+  //
+  // Publish Madt Structure to ACPI
+  //
+  Status = mAcpiTable->InstallAcpiTable (
+    mAcpiTable,
+    NewMadtTable,
+    NewMadtTable->Header.Length,
+    &TableHandle
+    );
+
+Done:
+  //
+  // Free memory
+  //
+  for (MadtStructsIndex = 0; MadtStructsIndex < MaxMadtStructCount; MadtStructsIndex++) {
+    if (MadtStructs[MadtStructsIndex] != NULL) {
+      FreePool (MadtStructs[MadtStructsIndex]);
+    }
+  }
+
+  FreePool (MadtStructs);
+
+  if (NewMadtTable != NULL) {
+    FreePool (NewMadtTable);
+  }
+
+  return Status;
+}

+ 1574 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibBdat.c

@@ -0,0 +1,1574 @@
+/** @file
+  ACPI Platform Driver Hooks
+
+  @copyright
+  Copyright 1996 - 2020 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include "AcpiPlatformLibLocal.h"
+#include <Library/CrcLib.h>
+#include <BdatSchema.h>
+#include <Guid/MemoryMapData.h>
+#include <Library/CompressedVariableLib.h>
+#include <Protocol/DynamicSiLibraryProtocol2.h>
+#include <Protocol/DynamicSiLibraryProtocol2.h>
+
+extern struct SystemMemoryMapHob   *mSystemMemoryMap;
+extern EFI_IIO_UDS_PROTOCOL        *mIioUds;
+
+#include <Acpi/Bdat.h>
+
+#ifndef MAX_HOB_ENTRY_SIZE
+#define MAX_HOB_ENTRY_SIZE  60*1024
+#endif
+
+/**
+  Save BSSA results to BDAT
+
+  @param[in,out]   BdatHeaderStructPtr - Pointer to BDAT Structure
+  @param[in]       OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
+  @param[in]       SchemaStartAddress  - Starting address where the BSSA result schema will be added
+  @param[in, out]  SchemaIndex         - Current schema index inside the BDAT. Need it to update the schema offsets array.
+  @param[in]       SchemaSize          - The size of the BSSA results schema.
+  @param[out]      SchemaSpaceUsed     - The numebr bytes were filled in all schema
+  @param[out]      LastSchemaSpaceUsed - The numebr bytes were filled in the last schema
+
+  @retval EFI_SUCCESS  - BSSA BDAT scehma created successfully
+  @retval !EFI_SUCCESS - BSSA BDAT scehma creation failed
+**/
+EFI_STATUS
+SaveBssaResultsToBdat (
+  IN OUT BDAT_STRUCTURE          *BdatHeaderStructPtr,
+  IN     UINT32                  OffsetFromLastSchema,
+  IN     EFI_PHYSICAL_ADDRESS    *SchemaStartAddress,
+  IN OUT UINT8                   *SchemaIndex,
+  IN     UINT32                  SchemaSize,
+  OUT    UINT32                  *SchemaSpaceUsed,
+  OUT    UINT32                  *LastSchemaSpaceUsed
+  );
+
+/**
+  Save EWL results to BDAT
+
+  @param[in,out]   BdatHeaderStructPtr - Pointer to BDAT Structure
+  @param[in]       OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
+  @param[in]       SchemaStartAddress  - Starting address where the EWL schema will be added
+  @param[in, out]  SchemaIndex         - Current schema index inside the BDAT. Need it to update the schema offsets array.
+  @param[out]      SchemaSpaceUsed     - The numebr bytes were filled
+
+  @retval EFI_SUCCESS  - EWL BDAT scehma created successfully
+  @retval !EFI_SUCCESS - EWL BDAT scehma creation failed
+**/
+EFI_STATUS
+SaveEwlToBdat (
+  IN OUT BDAT_STRUCTURE          *BdatHeaderStructPtr,
+  IN     UINT32                  OffsetFromLastSchema,
+  IN     EFI_PHYSICAL_ADDRESS    *SchemaStartAddress,
+  IN OUT UINT8                   *SchemaIndex,
+  OUT    UINT32                  *SchemaSpaceUsed
+  );
+
+/**
+  Save SPD date structure to BDAT
+
+  @param[in,out]   BdatHeaderStructPtr - Pointer to BDAT Structure
+  @param[in]       OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
+  @param[in]       SchemaStartAddress  - Starting address where the SPD data schema will be added
+  @param[in, out]  SchemaIndex         - Current schema index inside the BDAT. Need it to update the schema offsets array.
+  @param[out]      SchemaSpaceUsed     - The numebr bytes were filled
+
+  @retval EFI_SUCCESS  - SPD BDAT scehma created successfully
+  @retval !EFI_SUCCESS - SPD BDAT scehma creation failed
+**/
+EFI_STATUS
+SaveSpdToBdat (
+  IN OUT BDAT_STRUCTURE          *BdatHeaderStructPtr,
+  IN     UINT32                  OffsetFromLastSchema,
+  IN     EFI_PHYSICAL_ADDRESS    *SchemaStartAddress,
+  IN OUT UINT8                   *SchemaIndex,
+  OUT    UINT32                  *SchemaSpaceUsed
+  );
+
+/**
+  Save memory training date structure to BDAT
+
+  @param[in,out]   BdatHeaderStructPtr - Pointer to BDAT Structure
+  @param[in]       OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
+  @param[in]       SchemaStartAddress  - Starting address where the memory training data schema will be added
+  @param[in, out]  SchemaIndex         - Current schema index inside the BDAT. Need it to update the schema offsets array.
+  @param[out]      SchemaSpaceUsed     - The numebr bytes were filled
+
+  @retval EFI_SUCCESS  - Memory training data BDAT scehma created successfully
+  @retval !EFI_SUCCESS - Memory training data BDAT scehma creation failed
+**/
+EFI_STATUS
+SaveTrainingDataToBdat (
+  IN OUT BDAT_STRUCTURE          *BdatHeaderStructPtr,
+  IN     UINT32                  OffsetFromLastSchema,
+  IN     EFI_PHYSICAL_ADDRESS    *SchemaStartAddress,
+  IN OUT UINT8                   *SchemaIndex,
+  OUT    UINT32                  *SchemaSpaceUsed
+  );
+
+/**
+  Get the size of SPD data structure not include the SPD BDAT schema header.
+
+  @retval UINT32 - Size of SPD data structure in bytes
+**/
+UINT32
+GetSpdDataSize (
+  VOID
+  );
+
+/**
+  Read the SPD data for one dimm and fill up SPD entry inside SPD BDAT schema space.
+
+  @param[out] Address           - Start Address of the buffer where the SPD entry to be filled
+  @param[in]  Socket            - Socket number
+  @param[in]  Channel           - Channel number inside the Socket
+  @param[in]  Dimm              - Dimm slot number
+  @param[in]  MaxSpdByteOffset  - The max SPD byte offset. DDR4 is 512
+
+  @retval EFI_SUCCESS  - SPD Structure filled successfully
+  @retval !EFI_SUCCESS - SPD structure creation failed
+**/
+EFI_STATUS
+FillSpdPerDimmEntry (
+  OUT EFI_PHYSICAL_ADDRESS    Address,
+  IN UINT8                    Socket,
+  IN UINT8                    Channel,
+  IN UINT8                    Dimm,
+  IN UINT16                   MaxSpdByteOffset
+  );
+
+/**
+  Fill the SPD data structure inside the BDAT schema space.
+
+  @param[out] StartAddress           - Start Address of the buffer where SPD data structure to be filled
+  @param[in]  SpdDataSize            - Size of SPD data structure includes the header
+
+  @retval EFI_SUCCESS  - SPD Structure filled successfully
+  @retval !EFI_SUCCESS - SPD structure creation failed
+**/
+EFI_STATUS
+FillSpdSchema (
+  OUT EFI_PHYSICAL_ADDRESS    StartAddress,
+  IN UINT32                   SpdDataSize
+  );
+
+/**
+  Displays SPD content for debugging.
+
+  @param[in] Address  - The starting address of the SPD entry
+
+  @retval N/A
+**/
+VOID
+DisplaySpdContents (
+  IN EFI_PHYSICAL_ADDRESS  Address
+  );
+
+/**
+  Get Number of Schemas From BSSA HOB
+
+  @retval UINT16 - Number of BSSA Schemas
+**/
+UINT16
+GetNumberOfSchemasFromBssaHob (
+  VOID
+  )
+{
+  UINT32                          GuidIdx = 0;
+  UINT16                          NumberOfBssaSchemas = 0;
+  EFI_STATUS                      Status = EFI_SUCCESS;
+  DYNAMIC_SI_LIBARY_PROTOCOL      *DynamicSiLibraryProtocol = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return 0;
+  }
+
+  if (mSystemMemoryMap == NULL) {
+    mSystemMemoryMap = DynamicSiLibraryProtocol->GetSystemMemoryMapData ();
+  }
+
+  ASSERT (mSystemMemoryMap != NULL);
+  if (mSystemMemoryMap == NULL) {
+    return 0;
+  }
+
+  for (GuidIdx = 0; GuidIdx < mSystemMemoryMap->Reserved9; GuidIdx++) {
+    //
+    // No. of HOBS per GUID added up for all GUIDs created from calls to saveToBdat ()
+    //
+    NumberOfBssaSchemas += mSystemMemoryMap->Reserved7[GuidIdx];
+    DEBUG ((DEBUG_VERBOSE, "GuidIdx = %d, total num hobs: %d\n", GuidIdx,  mSystemMemoryMap->Reserved7[GuidIdx]));
+  }
+  return NumberOfBssaSchemas;
+}
+
+/**
+  Create BDAT Header with necessary information.
+  Allocate memory with BdatSize and if failure return status.
+  If Success return the pointer address for copying the schema information
+
+  @param[out] BdatHeaderStructPtr - Pointer to BDAT Structure
+  @param[in]  BdatSize            - Size of BDAT Structure
+  @param[in]  NumberOfSchema      - Total nunber of of schema
+
+  @retval EFI_SUCCESS  - BDAT Structure created successfully
+  @retval !EFI_SUCCESS - BDAT structure creation failed
+**/
+EFI_STATUS
+CreateBdatHeader (
+  OUT BDAT_STRUCTURE **BdatHeaderStructPtr,
+  IN UINT32          BdatSize,
+  IN UINT16          NumberOfSchema
+  )
+{
+  EFI_TIME                      EfiTime;
+  UINT64                        Address = 0xffffffff;
+  EFI_STATUS                    Status = EFI_SUCCESS;
+
+  //
+  // Allocating RealTime Memory for BDAT.
+  //
+
+  Status = gBS->AllocatePages (
+    AllocateMaxAddress,
+    EfiACPIMemoryNVS,
+    EFI_SIZE_TO_PAGES(BdatSize),
+    &Address
+  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // The memory location where the HOB's are to be copied to
+  //
+  ZeroMem ((VOID *)Address, BdatSize);
+
+  *BdatHeaderStructPtr = (BDAT_STRUCTURE *)Address;
+
+  DEBUG ((DEBUG_VERBOSE, "\nBDAT Allocated Address = %x\n", Address));
+
+  //
+  // Create BIOS Data Signature
+  //
+  (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[0] = 'B';
+  (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[1] = 'D';
+  (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[2] = 'A';
+  (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[3] = 'T';
+  (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[4] = 'H';
+  (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[5] = 'E';
+  (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[6] = 'A';
+  (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[7] = 'D';
+  //
+  // Structure size
+  //
+  (*BdatHeaderStructPtr)->BdatHeader.BiosDataStructSize = BdatSize;
+  //
+  // Primary Version
+  //
+  (*BdatHeaderStructPtr)->BdatHeader.PrimaryVersion = BDAT_PRIMARY_VER;
+  //
+  // Secondary Version
+  //
+  (*BdatHeaderStructPtr)->BdatHeader.SecondaryVersion = BDAT_SECONDARY_VER;
+  //
+  // CRC16 value of the BDAT_STRUCTURE
+  //
+  (*BdatHeaderStructPtr)->BdatHeader.Crc16 = 0;
+  Status = CalculateCrc16 (
+    (VOID *)(*BdatHeaderStructPtr),
+    BdatSize,
+    &(*BdatHeaderStructPtr)->BdatHeader.Crc16
+  );
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    (*BdatHeaderStructPtr)->BdatHeader.Crc16 = 0xFFFF;
+  }
+  (*BdatHeaderStructPtr)->BdatSchemas.SchemaListLength = NumberOfSchema;
+  (*BdatHeaderStructPtr)->BdatSchemas.Reserved = 0;
+  (*BdatHeaderStructPtr)->BdatSchemas.Reserved1 = 0;
+  //
+  // Initialize the Time parameters in the SCHEMA_LIST_STRUCTURE
+  //
+  Status = gRT->GetTime (&EfiTime, NULL);
+  if (!EFI_ERROR (Status)) {
+    (*BdatHeaderStructPtr)->BdatSchemas.Year = EfiTime.Year;
+    (*BdatHeaderStructPtr)->BdatSchemas.Month = EfiTime.Month;
+    (*BdatHeaderStructPtr)->BdatSchemas.Day = EfiTime.Day;
+    (*BdatHeaderStructPtr)->BdatSchemas.Hour = EfiTime.Hour;
+    (*BdatHeaderStructPtr)->BdatSchemas.Minute = EfiTime.Minute;
+    (*BdatHeaderStructPtr)->BdatSchemas.Second = EfiTime.Second;
+  }
+  return Status;
+}
+
+/**
+  Dump BDAT Table to serial log
+
+  Example 1: There are 2 schema: BSSA RMT and EWL.
+
+  Print BDAT Table
+  Address     0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
+  00000000 0x42 0x44 0x41 0x54 0x48 0x45 0x41 0x44 0x30 0x18 0x00 0x00 0xD7 0x7A 0x00 0x00
+  00000010 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+  00000020 0x02 0x00 0x00 0x00 0xE4 0x07 0x08 0x0E 0x00 0x29 0x03 0x00 0x34 0x00 0x00 0x00
+  00000030 0xFA 0x07 0x00 0x00 0x28 0xE9 0xF4 0x08 0x5F 0x0F 0xD4 0x46 0x84 0x10 0x47 0x9F
+  00000040 0xDA 0x27 0x9D 0xB6 0xC6 0x07 0x00 0x00 0x57 0x7F 0x00 0x00 0x00 0x00 0x00 0xA5
+  00000050 0x98 0x88 0xFE 0x4C 0x00 0x00 0x00 0x0D 0xEB 0x7A 0x47 0x07 0xDE 0x77 0x42 0xA4
+  00000060 0xE7 0x87 0x81 0x0B 0x10 0x00 0x31 0xF1 0x98 0x88 0xFE 0xF2 0x45 0x81 0xD9 0xF4
+  ...
+  ...
+  000007F0 0x00 0x00 0x00 0x5A 0xA5 0x5A 0xA5 0x5A 0xA5 0x5A 0x2F 0x53 0xFE 0xBF 0x3B 0xCA
+  00000800 0x6C 0x41 0xA0 0xF6 0xFF 0xE4 0xE7 0x1E 0x3A 0x0D 0x36 0x10 0x00 0x00 0x9F 0xEF
+  00000810 0x70 0x33 0x71 0x75 0x05 0x38 0xB0 0x46 0x9F 0xED 0x60 0xF2 0x82 0x48 0x6C 0xFC
+  00000820 0x20 0x10 0x00 0x00 0x12 0x00 0x00 0x00 0x2E 0x81 0x50 0x51 0x00 0x00 0x00 0x00
+  00000830 0x01 0x00 0x00 0x00 0x12 0x00 0x01 0x00 0x00 0x00 0x7E 0x07 0x17 0x18 0x01 0xFF
+  00000840 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+
+  Example 2: There is 1 schema: EWL
+  Address     0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
+  00000000 0x42 0x44 0x41 0x54 0x48 0x45 0x41 0x44 0x66 0x10 0x00 0x00 0xA9 0x44 0x00 0x00
+  00000010 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+  00000020 0x01 0x00 0x00 0x00 0xE4 0x07 0x08 0x0E 0x01 0x0F 0x2C 0x00 0x30 0x00 0x00 0x00
+  00000030 0x2F 0x53 0xFE 0xBF 0x3B 0xCA 0x6C 0x41 0xA0 0xF6 0xFF 0xE4 0xE7 0x1E 0x3A 0x0D
+  00000040 0x36 0x10 0x00 0x00 0x9F 0xEF 0x70 0x33 0x71 0x75 0x05 0x38 0xB0 0x46 0x9F 0xED
+  00000050 0x60 0xF2 0x82 0x48 0x6C 0xFC 0x20 0x10 0x00 0x00 0x12 0x00 0x00 0x00 0x2E 0x81
+  00000060 0x50 0x51 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x12 0x00 0x01 0x00 0x00 0x00
+  00000070 0x7E 0x07 0x17 0x18 0x01 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+  00000080 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+
+  @param[out] BdatHeaderStructPtr - Pointer to BDAT Structure
+  @param[in]  BdatSize            - Size of BDAT Structure
+
+  @retval None
+**/
+VOID
+DumpBdatTable(
+  IN BDAT_STRUCTURE **BdatHeaderStructPtr,
+  IN UINT32 BdatSize
+)
+{
+  UINT32  i = 0;
+  UINT8   *Table = NULL;
+
+  Table = (UINT8 *)(*BdatHeaderStructPtr);
+  DEBUG ((DEBUG_VERBOSE, "\nPrint BDAT Table\n"));
+
+  //
+  // Print address header
+  //
+  DEBUG ((DEBUG_VERBOSE, "Address "));
+  for (i = 0; i < 16; i++) {
+    DEBUG ((DEBUG_VERBOSE, "    %01x", i));
+  }
+
+  i = 0;
+  while (i < BdatSize) {
+    if ((i % 16) == 0) {
+      DEBUG ((DEBUG_VERBOSE, "\n%08x ", (i / 16) * 16));
+    } else {
+      DEBUG ((DEBUG_VERBOSE, " "));
+    }
+
+    DEBUG ((DEBUG_VERBOSE, "0x%02x", Table[i]));
+
+    if (i == BdatSize - 1) {
+      DEBUG ((DEBUG_VERBOSE, "\n"));
+    }
+
+    i++;
+
+  }
+  DEBUG ((DEBUG_VERBOSE, "\n"));
+}
+
+/**
+  Copy BDAT Table pointer to scratchpad 5 register
+
+  @param[in] BdatAddress - Bdat Table Address to be copied to Scratchpad 5 register
+
+  @retval None
+**/
+VOID
+CopyBdatPointerToScratchPad5 (
+  IN UINT64 BdatAddress
+  )
+{
+  UINT8                           Socket = 0;
+  EFI_STATUS                      Status = EFI_SUCCESS;
+  DYNAMIC_SI_LIBARY_PROTOCOL      *DynamicSiLibraryProtocol = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return;
+  }
+
+  //
+  // Copy BDAT base address to ScratchPad5
+  //
+  for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+    if (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].Valid) {
+      DynamicSiLibraryProtocol->WriteScratchpad5 (Socket, (UINT32) BdatAddress);
+      DEBUG ((DEBUG_VERBOSE, "Scratchpad_Debug PatchBdaAcpiTable: Verify Non Sticky Scratchpad5 0x%08x\n", BdatAddress));
+    }
+  }
+}
+
+/**
+    Update the BDAT ACPI table: Multiple instances of the BDAT DATA HOB are placed into one contiguos memory range
+
+    @param *TableHeader   - The table to be set
+
+    @retval EFI_SUCCESS -  Returns Success
+**/
+EFI_STATUS
+PatchBdatAcpiTable (
+  IN OUT  EFI_ACPI_COMMON_HEADER  *Table
+  )
+{
+  EFI_STATUS                        Status = EFI_SUCCESS;
+  EFI_PHYSICAL_ADDRESS              Address = 0;
+  UINT32                            Idx = 0;
+  UINT8                             Checksum = 0;
+  BDAT_STRUCTURE                    *BdatHeaderStructPtr = NULL;
+  UINT32                            TotalBDATstructureSize = 0;
+  UINT32                            BdatHeaderSize = 0;
+  EFI_HOB_GUID_TYPE                 *GuidHob = NULL;
+  UINT16                            NumberBssaSchemas = 0;
+  UINT16                            TotalNumberSchemas = 0;
+  UINT32                            BssaSchemaSize = 0;
+  EFI_BDAT_ACPI_DESCRIPTION_TABLE   *BdatAcpiTable = NULL;
+  EWL_PRIVATE_DATA                  *EwlPrivateData = NULL;
+  EFI_GUID                          EWLDataGuid = EWL_ID_GUID;
+  UINT32                            EwlSchemaSize = 0;
+  MEM_TRAINING_DATA_STRUCTURE       *MemTrainingData = NULL;
+  MEM_TRAINING_DATA_HOB_HEADER      *TrainingDataHobHeader = NULL;
+  UINT32                            TrainingDataSchemaSize = 0;
+  UINT32                            RemainingSchemaSpace = 0;
+  UINT32                            SpdDataSize = 0;
+  UINT32                            SpdSchemaSize = 0;
+  UINT8                             SchemaIndex = 0;
+  UINT32                            SpaceUsed = 0;
+  UINT32                            LastSchemaSpaceUsed = 0;
+  UINT32                            OffsetFromLastSchema = 0;
+
+  BdatAcpiTable = (EFI_BDAT_ACPI_DESCRIPTION_TABLE *)Table;
+  DEBUG ((DEBUG_INFO, "\nPatchBdatAcpiTable Started\n"));
+
+  //
+  // Gather BSSA schema info
+  //
+  NumberBssaSchemas = GetNumberOfSchemasFromBssaHob ();
+
+  BssaSchemaSize = mSystemMemoryMap->Reserved6 + (NumberBssaSchemas * sizeof (BDAT_SCHEMA_HEADER_STRUCTURE)); //Total size of all HOBs created by SaveToBdat() + NumberBssaSchemas*headerPerSchema
+  DEBUG ((DEBUG_VERBOSE, "NumberBssaSchemas = %d, total BSSA schema size: %d\n", NumberBssaSchemas, BssaSchemaSize));
+
+  TotalNumberSchemas = NumberBssaSchemas;
+
+  TotalBDATstructureSize += BssaSchemaSize;
+
+  //
+  // Gather EWL schema info
+  //
+  GuidHob = GetFirstGuidHob (&EWLDataGuid);
+  if (GuidHob != NULL) {
+    DEBUG ((DEBUG_VERBOSE, "Found EWL with GUID  %g\n", &EWLDataGuid));
+
+    TotalNumberSchemas += 1;
+
+    EwlPrivateData = GET_GUID_HOB_DATA (GuidHob);
+
+    EwlSchemaSize = sizeof (BDAT_SCHEMA_HEADER_STRUCTURE) + EwlPrivateData->status.Header.Size;
+
+    DEBUG ((DEBUG_VERBOSE, "EWL schema size: %d\n", EwlSchemaSize));
+
+    TotalBDATstructureSize += EwlSchemaSize;
+  }
+
+  //
+  // Gather SPD schema info
+  //
+  SpdSchemaSize = 0;
+  if (PcdGetBool (SaveSpdToBdat)) {
+    SpdDataSize = GetSpdDataSize ();
+
+    if (SpdDataSize > 0) {
+      TotalNumberSchemas += 1;
+      SpdSchemaSize = sizeof (BDAT_SCHEMA_HEADER_STRUCTURE) + SpdDataSize;
+      DEBUG ((DEBUG_VERBOSE, "SPD data schema size: %d\n", SpdSchemaSize));
+
+      TotalBDATstructureSize += SpdSchemaSize;
+    }
+  } // PcdGetBool (SaveSpdToBdat)
+
+  //
+  // Gather Memory training data schema info
+  //
+  TrainingDataSchemaSize = 0;
+  if (PcdGetBool (SaveMrcTrainingDataToBdat)) {
+    GuidHob = GetFirstGuidHob (&gMemTrainingDataHobGuid);
+    if (GuidHob != NULL) {
+      DEBUG ((DEBUG_VERBOSE, "Found memory training data HOB with GUID  %g\n", &gMemTrainingDataHobGuid));
+
+      TotalNumberSchemas += 1;
+
+      TrainingDataHobHeader = GET_GUID_HOB_DATA (GuidHob);
+
+      MemTrainingData = (MEM_TRAINING_DATA_STRUCTURE *)((EFI_PHYSICAL_ADDRESS)TrainingDataHobHeader + sizeof (MEM_TRAINING_DATA_HOB_HEADER));
+
+      TrainingDataSchemaSize = sizeof (BDAT_SCHEMA_HEADER_STRUCTURE) + MemTrainingData->Header.Size;
+
+      DEBUG ((DEBUG_VERBOSE, "Memory training data schema size: %d\n", TrainingDataSchemaSize));
+
+      TotalBDATstructureSize += TrainingDataSchemaSize;
+    }
+  } // PcdGetBool (SaveMrcTrainingDataToBdat)
+
+  BdatHeaderSize = sizeof (BDAT_STRUCTURE) + (TotalNumberSchemas * (sizeof (UINT32)));
+  TotalBDATstructureSize += BdatHeaderSize;
+
+  //
+  // This variable is used to keep track the remain space in the BDAT payload (schema section) to
+  // prevent overflow the allocated RT BDAT buffer.
+  //
+  RemainingSchemaSpace = TotalBDATstructureSize - BdatHeaderSize;
+
+  DEBUG ((DEBUG_INFO, "Total BDAT size:%d, BDAT header size: %d, Total schema:%d \n", TotalBDATstructureSize, BdatHeaderSize, TotalNumberSchemas));
+
+  Status = CreateBdatHeader (&BdatHeaderStructPtr, TotalBDATstructureSize, TotalNumberSchemas);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  DEBUG ((DEBUG_INFO, "BdatRegionAddress = 0x%x\n", (UINT64)BdatHeaderStructPtr));
+  CopyBdatPointerToScratchPad5 ((UINT64)BdatHeaderStructPtr);
+
+  //
+  // Update BDAT ACPI table
+  //
+  BdatAcpiTable->BdatGas.Address = (UINT64)BdatHeaderStructPtr;
+
+  //
+  // Starting address of the first schema
+  //
+  Address = (EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + BdatHeaderSize;
+
+  //
+  // Saving to RT Memory BDAT Data received from HOBs generated due to BSSA call/calls to SaveToBdat()
+  //
+  SpaceUsed = 0;
+
+  //
+  // The first schema starts right after the BDAT header structure
+  //
+  LastSchemaSpaceUsed = BdatHeaderSize;  // It will used as the OffsetFromLastSchema for the next schema if BSSA is not available
+  OffsetFromLastSchema = BdatHeaderSize;
+
+  if (BssaSchemaSize > 0) {
+
+    Status = SaveBssaResultsToBdat (BdatHeaderStructPtr, OffsetFromLastSchema, &Address, &SchemaIndex, BssaSchemaSize, &SpaceUsed, &LastSchemaSpaceUsed);
+    if (Status != EFI_SUCCESS) {
+      DEBUG ((DEBUG_ERROR, "Faield to add BSSA result to BDAT\n"));
+    }
+  }
+
+  //
+  // Update the starting address of next schema and remaining space.
+  //
+  Address += SpaceUsed;
+  RemainingSchemaSpace -= SpaceUsed;
+  OffsetFromLastSchema = LastSchemaSpaceUsed;
+
+  //
+  // Saving to RT Memory BDAT Data received from EWL HOB
+  //
+  SpaceUsed = 0;
+
+  if (EwlSchemaSize > 0) {
+
+    if (RemainingSchemaSpace < EwlSchemaSize) {
+      DEBUG ((DEBUG_ERROR, "Not enough space to add EWL schema.\n"));
+      goto End;
+    }
+
+    Status = SaveEwlToBdat (BdatHeaderStructPtr, OffsetFromLastSchema ,&Address, &SchemaIndex, &SpaceUsed);
+
+    if (Status != EFI_SUCCESS) {
+      DEBUG ((DEBUG_ERROR, "Failed to add EWL to BDAT.\n"));
+    }
+
+  }
+
+  //
+  // Update the starting address of next schema and remaining space.
+  //
+  Address += SpaceUsed;
+  RemainingSchemaSpace -= SpaceUsed;
+  OffsetFromLastSchema = SpaceUsed;
+
+  //
+  // Add SPD schema
+  //
+  SpaceUsed = 0;
+
+  if (SpdSchemaSize > 0) {
+
+    if (RemainingSchemaSpace < SpdSchemaSize) {
+      DEBUG ((DEBUG_ERROR, "Not enough space to add SPD schema.\n"));
+      goto End;
+    }
+
+    Status = SaveSpdToBdat (BdatHeaderStructPtr, OffsetFromLastSchema, &Address, &SchemaIndex, &SpaceUsed);
+
+    if (Status != EFI_SUCCESS) {
+      DEBUG ((DEBUG_ERROR, "Failed to add SPD to BDAT.\n"));
+    }
+
+  }
+
+  //
+  // Update the starting address of next schema and remaining space.
+  //
+  Address += SpaceUsed;
+  RemainingSchemaSpace -= SpaceUsed;
+  OffsetFromLastSchema = SpaceUsed;
+
+  //
+  // Add memory training data schema
+  //
+  SpaceUsed = 0;
+
+  if (TrainingDataSchemaSize > 0) {
+
+    if (RemainingSchemaSpace < TrainingDataSchemaSize) {
+      DEBUG ((DEBUG_ERROR, "Not enough space to add memory training data schema.\n"));
+      goto End;
+    }
+
+    Status = SaveTrainingDataToBdat (BdatHeaderStructPtr, OffsetFromLastSchema, &Address, &SchemaIndex, &SpaceUsed);
+
+    if (Status != EFI_SUCCESS) {
+      DEBUG ((DEBUG_ERROR, "Failed to add memory training data to BDAT.\n"));
+    }
+  }
+
+  //
+  // Update the starting address of next schema and remaining space.
+  //
+  Address += SpaceUsed;
+  RemainingSchemaSpace -= SpaceUsed;
+  OffsetFromLastSchema = SpaceUsed;
+
+  DEBUG ((DEBUG_VERBOSE, "Final SchemaIndex:%d RemainingSchemaSpace:%d\n", SchemaIndex, RemainingSchemaSpace));
+
+  End:
+
+  //
+  // Update checksum
+  //
+  BdatAcpiTable->Header.Checksum = 0;
+  Checksum = 0;
+  for(Idx = 0; Idx < sizeof(EFI_BDAT_ACPI_DESCRIPTION_TABLE); Idx++) {
+    Checksum = Checksum + (UINT8) (((UINT8 *)(BdatAcpiTable))[Idx]);
+  }
+  BdatAcpiTable->Header.Checksum = (UINT8) (0 - Checksum);
+
+  DumpBdatTable (&BdatHeaderStructPtr, TotalBDATstructureSize);
+
+  return Status;
+}
+
+
+/**
+  Displays SPD content for debugging.
+
+  @param[in] Address  - The starting address of the SPD entry
+
+  @retval N/A
+**/
+VOID
+DisplaySpdContents (
+  IN EFI_PHYSICAL_ADDRESS  Address
+  )
+{
+  UINT16                  Index;
+  MEM_SPD_ENTRY_TYPE0    *EntryHeaderPtr;
+
+  EntryHeaderPtr = (MEM_SPD_ENTRY_TYPE0  *)Address;
+
+  //
+  // Print the Socket, Channel and Dimm information.
+  //
+  DEBUG ((DEBUG_VERBOSE, "START_PRINT_SPD S%dC%dD%d:\n",
+    EntryHeaderPtr->MemoryLocation.Socket,
+    EntryHeaderPtr->MemoryLocation.Channel,
+    EntryHeaderPtr->MemoryLocation.Dimm));
+
+  //
+  // Print the Column Number of the SPD data.
+  //
+  for (Index = 0; Index < 0x10; Index++) {
+    DEBUG ((DEBUG_VERBOSE, " %02x", Index));
+  }
+
+  Address += sizeof (MEM_SPD_ENTRY_TYPE0);
+
+  for (Index = 0; Index < EntryHeaderPtr->NumberOfBytes; Index++) {
+
+    //
+    // Print the Carriage Return and Byte Index of SPD data.
+    //
+    if ((Index % 0x10) == 0) {
+
+      //
+      // Split the SPD data for every 256 bytes
+      //
+      if (((Index % 0x100) == 0) && (Index != 0)) {
+        DEBUG ((DEBUG_VERBOSE, "\n"));
+      }
+
+      DEBUG ((DEBUG_VERBOSE, "\n%02x:", (UINT8) (Index & 0x00F0)));
+    }
+
+    DEBUG ((DEBUG_VERBOSE, " %02x", *(UINT8 *)(Address + (EFI_PHYSICAL_ADDRESS)Index)));
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "\n"));
+
+
+  DEBUG ((DEBUG_VERBOSE, "STOP_PRINT_SPD\n"));
+
+} // DisplaySpdContents
+
+/**
+  Get the size of SPD data structure not include the SPD BDAT schema header.
+
+  @retval UINT32 - Size of SPD data structure in bytes
+**/
+UINT32
+GetSpdDataSize (
+  VOID
+  )
+{
+  UINT32  SchemaSize = 0;
+  UINT8   Socket;
+  UINT8   Channel;
+  UINT8   Dimm;
+  UINT32  SpdBytesPerDimm = 0;
+  UINT8   NumberOfDimmPresent = 0;
+
+  EFI_STATUS                  Status = EFI_SUCCESS;
+  DYNAMIC_SI_LIBARY_PROTOCOL  *DynamicSiLibraryProtocol = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return 0;
+  }
+
+  if (mSystemMemoryMap == NULL) {
+    mSystemMemoryMap = DynamicSiLibraryProtocol->GetSystemMemoryMapData ();
+  }
+
+  if (mSystemMemoryMap == NULL) {
+    return 0;
+  }
+
+  ASSERT (mSystemMemoryMap->DramType == SPD_TYPE_DDR4);
+  SpdBytesPerDimm = MAX_SPD_BYTE_DDR4;
+
+  for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+    for (Channel = 0; Channel < MAX_CH; Channel++) {
+      for (Dimm = 0; Dimm < MAX_DIMM; Dimm++) {
+        if (mSystemMemoryMap->Socket[Socket].ChannelInfo[Channel].DimmInfo[Dimm].Present != 0) {
+          NumberOfDimmPresent += 1;
+        }
+      }
+    }
+  }
+
+  //
+  // Total entries
+  //
+  SchemaSize = (SpdBytesPerDimm + sizeof (MEM_SPD_ENTRY_TYPE0)) * NumberOfDimmPresent;
+
+  //
+  // Add the SPD raw data header
+  //
+  SchemaSize += sizeof (MEM_SPD_RAW_DATA_HEADER);
+
+  return SchemaSize;
+
+}
+
+
+/**
+  Read the SPD data for one dimm and fill up SPD entry inside SPD BDAT schema space.
+
+  @param[out] Address           - Start Address of the buffer where the SPD entry to be filled
+  @param[in]  Socket            - Socket number
+  @param[in]  Channel           - Channel number inside the Socket
+  @param[in]  Dimm              - Dimm slot number
+  @param[in]  MaxSpdByteOffset  - The max SPD byte offset. DDR4 is 512
+
+  @retval EFI_SUCCESS  - SPD Structure filled successfully
+  @retval !EFI_SUCCESS - SPD structure creation failed
+**/
+EFI_STATUS
+FillSpdPerDimmEntry (
+  OUT EFI_PHYSICAL_ADDRESS    Address,
+  IN UINT8                    Socket,
+  IN UINT8                    Channel,
+  IN UINT8                    Dimm,
+  IN UINT16                   MaxSpdByteOffset
+  )
+{
+  UINT16               SpdByteOffset = 0;
+  UINT8                SpdData = 0;
+  MEM_SPD_ENTRY_TYPE0  *EntryHeaderPtr;
+  EFI_STATUS           Status = EFI_SUCCESS;
+
+  DYNAMIC_SI_LIBARY_PROTOCOL2  *DynamicSiLibraryProtocol2 = NULL;
+
+  DEBUG ((DEBUG_VERBOSE, "Fill Spd entry for Socket:%d Channel:%d Dimm:%d at location:0x%x \n", Socket, Channel, Dimm, Address));
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  EntryHeaderPtr = (MEM_SPD_ENTRY_TYPE0  *)Address;
+
+  //
+  // Add the entry header. We use type 0.
+  //
+  EntryHeaderPtr->Header.Type = MemSpdDataType0;
+  EntryHeaderPtr->Header.Size = sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset;
+
+  EntryHeaderPtr->MemoryLocation.Socket = Socket;
+  EntryHeaderPtr->MemoryLocation.Channel = Channel;
+  EntryHeaderPtr->MemoryLocation.Dimm = Dimm;
+
+  EntryHeaderPtr->NumberOfBytes = MaxSpdByteOffset;
+
+  Address += sizeof (MEM_SPD_ENTRY_TYPE0);
+
+  for (SpdByteOffset = 0; SpdByteOffset < MaxSpdByteOffset; SpdByteOffset++) {
+    Status = DynamicSiLibraryProtocol2->SpdReadByte (Socket, Channel, Dimm, SpdByteOffset, &SpdData);
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_WARN, "Failed to read SPD data at Socket:%d Channel:%d Dimm:%d SpdByteOffset:%d Status:0x%x\n",
+        Socket, Channel, Dimm, SpdByteOffset, Status));
+      return Status;
+    }
+
+    *(UINT8 *)Address = SpdData;
+    Address += 1;
+  } // SpdByteOffset
+
+  return Status;
+}
+
+/**
+  Fill the SPD data structure inside the BDAT schema space.
+
+  @param[out] StartAddress           - Start Address of the buffer where SPD data structure to be filled
+  @param[in]  SpdDataSize            - Size of SPD data structure includes the header
+
+  @retval EFI_SUCCESS  - SPD Structure filled successfully
+  @retval !EFI_SUCCESS - SPD structure creation failed
+**/
+EFI_STATUS
+FillSpdSchema (
+  OUT EFI_PHYSICAL_ADDRESS    StartAddress,
+  IN UINT32                   SpdDataSize
+  )
+{
+  UINT8                   Socket;
+  UINT8                   Channel;
+  UINT8                   Dimm;
+  UINT16                  MaxSpdByteOffset = 0;
+  UINT32                  RemainedSpace;
+  EFI_PHYSICAL_ADDRESS    Address;
+  MEM_SPD_RAW_DATA_HEADER *SpdDataHeaderStructPtr;
+  EFI_STATUS              Status = EFI_SUCCESS;
+
+  DYNAMIC_SI_LIBARY_PROTOCOL  *DynamicSiLibraryProtocol = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  if (mSystemMemoryMap == NULL) {
+    mSystemMemoryMap = DynamicSiLibraryProtocol->GetSystemMemoryMapData ();
+  }
+
+  if (mSystemMemoryMap == NULL) {
+    return EFI_DEVICE_ERROR;;
+  }
+  if (StartAddress == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  RemainedSpace = SpdDataSize;
+  Address = StartAddress;
+  SpdDataHeaderStructPtr = (MEM_SPD_RAW_DATA_HEADER *)StartAddress;
+
+  //
+  // Fill up the header of the SPD data strcuture
+  //
+  SpdDataHeaderStructPtr->MemSpdGuid = gSpdVersion1Guid;
+  SpdDataHeaderStructPtr->Size = SpdDataSize;
+  SpdDataHeaderStructPtr->Reserved = 0;
+
+  Address += sizeof (MEM_SPD_RAW_DATA_HEADER);
+  RemainedSpace -= sizeof (MEM_SPD_RAW_DATA_HEADER);
+
+  ASSERT (mSystemMemoryMap->DramType == SPD_TYPE_DDR4);
+  MaxSpdByteOffset = MAX_SPD_BYTE_DDR4;
+
+  //
+  // Iterate through all populated DIMMs and add them
+  //
+  for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+    for (Channel = 0; Channel < MAX_CH; Channel++) {
+      for (Dimm = 0; Dimm < MAX_DIMM; Dimm++) {
+
+        if (mSystemMemoryMap->Socket[Socket].ChannelInfo[Channel].DimmInfo[Dimm].Present != 0) {
+
+          if (RemainedSpace < sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset) {
+            DEBUG ((DEBUG_ERROR, "Run out of allocated SPD data space. RemainedSpace:%d required space:%d\n",
+              RemainedSpace, sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset));
+            return RETURN_OUT_OF_RESOURCES;
+          }
+
+          Status = FillSpdPerDimmEntry (Address, Socket, Channel, Dimm, MaxSpdByteOffset);
+          if (EFI_ERROR (Status)) {
+            DEBUG ((DEBUG_ERROR, "Failed to read SPD data at Socket:%d Channel:%d Dimm:%d Status:0x%x.\n",  Socket, Channel, Dimm, Status));
+            return Status;
+          }
+
+          DisplaySpdContents (Address);
+
+          Address += sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset;
+          RemainedSpace -= sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset;
+
+        }
+      } // Dimm
+    } // Channel
+  } // Socket
+
+  //
+  // Update CRC
+  //
+  SpdDataHeaderStructPtr->Crc = 0;
+  SpdDataHeaderStructPtr->Crc = CalculateCrc32 ((VOID *) SpdDataHeaderStructPtr, SpdDataHeaderStructPtr->Size);
+
+  return EFI_SUCCESS;
+
+}
+
+/**
+  Save BSSA results to BDAT
+
+  @param[in,out]   BdatHeaderStructPtr - Pointer to BDAT Structure
+  @param[in]       OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
+  @param[in]       SchemaStartAddress  - Starting address where the BSSA result schema will be added
+  @param[in, out]  SchemaIndex         - Current schema index inside the BDAT. Need it to update the schema offsets array.
+  @param[in]       SchemaSize          - The size of the BSSA results schema.
+  @param[out]      SchemaSpaceUsed     - The numebr bytes were filled in all schema
+  @param[out]      LastSchemaSpaceUsed - The numebr bytes were filled in the last schema
+
+  @retval EFI_SUCCESS  - BSSA BDAT scehma created successfully
+  @retval !EFI_SUCCESS - BSSA BDAT scehma creation failed
+**/
+EFI_STATUS
+SaveBssaResultsToBdat (
+  IN OUT BDAT_STRUCTURE          *BdatHeaderStructPtr,
+  IN     UINT32                  OffsetFromLastSchema,
+  IN     EFI_PHYSICAL_ADDRESS    *SchemaStartAddress,
+  IN OUT UINT8                   *SchemaIndex,
+  IN     UINT32                  SchemaSize,
+  OUT    UINT32                  *SchemaSpaceUsed,
+  OUT    UINT32                  *LastSchemaSpaceUsed
+  )
+{
+  EFI_STATUS                        Status                      = EFI_SUCCESS;
+  UINT32                            *SchemaAddrLocationArray    = NULL;
+  UINT32                            CurrentHobSize              = 0;
+  EFI_HOB_GUID_TYPE                 *GuidHob                    = NULL;
+  VOID                              *HobData                    = NULL;
+  UINT32                            PreviousSchemaSize          = 0;
+  EFI_GUID                          gEfiMemoryMapDataHobBdatBssaGuid  = {0};
+  UINT32                            GuidIdx                     = 0;
+  UINT32                            HobIdx                      = 0;
+  UINT32                            RemainingHobSizeBssaSchema  = 0;
+  BDAT_SCHEMA_HEADER_STRUCTURE      *BssaSchemaHeaderPtr        = NULL;
+  EFI_PHYSICAL_ADDRESS              Address                     = 0;
+
+  if ((BdatHeaderStructPtr == NULL) || (SchemaStartAddress == NULL) || (SchemaIndex == NULL) || (SchemaSpaceUsed == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  RemainingHobSizeBssaSchema = SchemaSize;
+  Address = *SchemaStartAddress;
+  *SchemaSpaceUsed = 0;
+
+  //
+  // Update the schema offset array for its first BSSA schema
+  //
+  SchemaAddrLocationArray = (UINT32 *)((EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + sizeof(BDAT_STRUCTURE));
+
+  if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) {
+    if (*SchemaIndex == 0) {
+      SchemaAddrLocationArray[*SchemaIndex] = OffsetFromLastSchema;
+    }
+    else {
+      SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + OffsetFromLastSchema;
+    }
+  }
+
+  for (GuidIdx = 0; GuidIdx < mSystemMemoryMap->Reserved9; GuidIdx++) {
+
+    gEfiMemoryMapDataHobBdatBssaGuid  = mSystemMemoryMap->Reserved8[GuidIdx]; //get first GUID instance
+    GuidHob = GetFirstGuidHob (&gEfiMemoryMapDataHobBdatBssaGuid);
+
+    for (HobIdx = 0; HobIdx < mSystemMemoryMap->Reserved7[GuidIdx]; HobIdx++) { //looping through all HOBs linked to that GUID
+
+      ASSERT (GuidHob != NULL);
+      if (GuidHob == NULL) {
+        return EFI_NOT_FOUND;
+      }
+
+      HobData = GET_GUID_HOB_DATA (GuidHob);
+      CurrentHobSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
+      DEBUG ((DEBUG_VERBOSE, "Initial HOB size  %d; remaining HOB size %d\n", CurrentHobSize, RemainingHobSizeBssaSchema));
+
+      //
+      // Setting the header first
+      //
+      if (RemainingHobSizeBssaSchema < sizeof(BDAT_SCHEMA_HEADER_STRUCTURE)) {
+        //
+        // Nothing we can do, break execution
+        //
+        DEBUG ((DEBUG_WARN, "Not enough space to add schema header to BIOS SSA result\n"));
+        RemainingHobSizeBssaSchema = 0;
+        break;
+      }
+
+      //
+      // Each HOB has a header added to it (BDAT_SCHEMA_HEADER_STRUCTURE)
+      //
+      Address = Address + (EFI_PHYSICAL_ADDRESS)PreviousSchemaSize;
+
+      BssaSchemaHeaderPtr = (BDAT_SCHEMA_HEADER_STRUCTURE *)Address;
+      BssaSchemaHeaderPtr->SchemaId = gEfiMemoryMapDataHobBdatBssaGuid;
+      RemainingHobSizeBssaSchema -= sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
+      *SchemaSpaceUsed = *SchemaSpaceUsed + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
+
+      Address = Address + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
+
+      //
+      // CRC16 value of the BDAT_SCHEMA_HEADER_STRUCTURE
+      //
+      BssaSchemaHeaderPtr->Crc16 = 0;
+      Status = CalculateCrc16 (
+        (VOID *) BssaSchemaHeaderPtr,
+        sizeof (BDAT_SCHEMA_HEADER_STRUCTURE),
+        &BssaSchemaHeaderPtr->Crc16
+        );
+      ASSERT_EFI_ERROR (Status);
+      if (EFI_ERROR (Status)) {
+        BssaSchemaHeaderPtr->Crc16 = 0xFFFF;
+      }
+
+      if (RemainingHobSizeBssaSchema < CurrentHobSize) {
+        DEBUG ((DEBUG_WARN, "Not enough space to add complete BIOS SSA result\n"));
+        CurrentHobSize = RemainingHobSizeBssaSchema;
+      }
+
+      //
+      // HOB size won't overflow a UINT32.
+      //
+      BssaSchemaHeaderPtr->DataSize = (UINT32)CurrentHobSize + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
+      DEBUG ((DEBUG_VERBOSE, "Setting schema %g size to %d\n", &(BssaSchemaHeaderPtr->SchemaId), BssaSchemaHeaderPtr->DataSize));
+      //
+      // HOB size won't overflow a UINT32.
+      //
+      PreviousSchemaSize = (UINT32)CurrentHobSize + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
+
+      //
+      // Copy HOB to RT Memory
+      //
+      CopyMem ((VOID *)Address, (VOID *)HobData, (UINT32)CurrentHobSize);
+      //
+      // HOB size won't overflow a UINT32.
+      //
+      DEBUG ((DEBUG_VERBOSE, "HOB size  %d; remaining SSA HOB size %d\n", CurrentHobSize, RemainingHobSizeBssaSchema));
+      RemainingHobSizeBssaSchema -= (UINT32)CurrentHobSize;
+      *SchemaSpaceUsed = *SchemaSpaceUsed + (UINT32)CurrentHobSize;
+
+      *SchemaIndex = *SchemaIndex + 1;
+
+      if (RemainingHobSizeBssaSchema == 0) {
+        break;
+      }
+
+      GuidHob = GET_NEXT_HOB (GuidHob); // Increment to next HOB
+      GuidHob = GetNextGuidHob (&gEfiMemoryMapDataHobBdatBssaGuid, GuidHob);  // Now search for next instance of the BDAT HOB
+      if (GuidHob == NULL) {
+        break;
+      }
+
+      //
+      // Update the schema offset arrary
+      //
+      if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) {
+        SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + PreviousSchemaSize;
+      }
+    }
+
+    if (RemainingHobSizeBssaSchema == 0) {
+      break;
+    }
+
+  }
+
+  *LastSchemaSpaceUsed = PreviousSchemaSize;
+
+  return EFI_SUCCESS;
+} // SaveBssaResultsToBdat
+
+
+/**
+  Save EWL results to BDAT
+
+  @param[in,out]   BdatHeaderStructPtr - Pointer to BDAT Structure
+  @param[in]       OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
+  @param[in]       SchemaStartAddress  - Starting address where the EWL schema will be added
+  @param[in, out]  SchemaIndex         - Current schema index inside the BDAT. Need it to update the schema offsets array.
+  @param[out]      SchemaSpaceUsed     - The numebr bytes were filled
+
+  @retval EFI_SUCCESS  - EWL BDAT scehma created successfully
+  @retval !EFI_SUCCESS - EWL BDAT scehma creation failed
+**/
+EFI_STATUS
+SaveEwlToBdat (
+  IN OUT BDAT_STRUCTURE          *BdatHeaderStructPtr,
+  IN     UINT32                  OffsetFromLastSchema,
+  IN     EFI_PHYSICAL_ADDRESS    *SchemaStartAddress,
+  IN OUT UINT8                   *SchemaIndex,
+  OUT    UINT32                  *SchemaSpaceUsed
+  )
+{
+  EFI_STATUS                        Status                      = EFI_SUCCESS;
+  UINT32                            *SchemaAddrLocationArray    = NULL;
+  EFI_HOB_GUID_TYPE                 *GuidHob                    = NULL;
+  EFI_PHYSICAL_ADDRESS              Address                     = 0;
+  EWL_PRIVATE_DATA                  *EwlPrivateData             = NULL;
+  EFI_GUID                          EWLDataGuid                 = EWL_ID_GUID;
+  BDAT_SCHEMA_HEADER_STRUCTURE      *EwlSchemaHeaderPtr         = NULL;
+  UINT32                            EwlSize                     = 0;
+
+  if ((BdatHeaderStructPtr == NULL) || (SchemaStartAddress == NULL) || (SchemaIndex == NULL) || (SchemaSpaceUsed == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Address = *SchemaStartAddress;
+  *SchemaSpaceUsed = 0;
+
+  DEBUG ((DEBUG_VERBOSE, "\nStarting to copy EWL schema at Address = 0x%x\n", Address));
+
+  //
+  // Update the schema offset arrary
+  //
+  SchemaAddrLocationArray = (UINT32 *)((EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + sizeof(BDAT_STRUCTURE));
+
+  if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) {
+    if (*SchemaIndex == 0) {
+      SchemaAddrLocationArray[*SchemaIndex] = OffsetFromLastSchema;
+    }
+    else {
+      SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + OffsetFromLastSchema;
+    }
+  }
+
+  EwlSchemaHeaderPtr = (BDAT_SCHEMA_HEADER_STRUCTURE *)Address;
+  EwlSchemaHeaderPtr->SchemaId = gEwlBdatSchemaGuid;
+  *SchemaSpaceUsed = *SchemaSpaceUsed + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
+
+  //
+  // CRC16 value of the BDAT_SCHEMA_HEADER_STRUCTURE
+  //
+  EwlSchemaHeaderPtr->Crc16 = 0;
+  Status = CalculateCrc16 (
+    (VOID *)EwlSchemaHeaderPtr,
+    sizeof(BDAT_SCHEMA_HEADER_STRUCTURE),
+    &EwlSchemaHeaderPtr->Crc16
+  );
+
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    EwlSchemaHeaderPtr->Crc16 = 0xFFFF;
+  }
+
+  GuidHob = GetFirstGuidHob (&EWLDataGuid);
+  EwlPrivateData = GET_GUID_HOB_DATA (GuidHob);
+
+  EwlSize = EwlPrivateData->status.Header.Size;
+
+  EwlSchemaHeaderPtr->DataSize = EwlSize + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
+
+  //
+  // Copy EWL HOB to RT Memory
+  //
+  Address = Address + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
+  CopyMem ((VOID *)Address, (VOID *)&(EwlPrivateData->status), EwlSize);
+  *SchemaSpaceUsed = *SchemaSpaceUsed + EwlSize;
+
+  *SchemaIndex = *SchemaIndex + 1;
+
+  return EFI_SUCCESS;
+} //SaveEwlToBdat
+
+/**
+  Check if current boot is slow boot or not
+
+  @retval TRUE  - Slow boot path
+  @retval FALSE - not slow boot path
+  **/
+BOOLEAN
+IsSlowBoot (
+  VOID
+  )
+{
+  EFI_STATUS                      Status = EFI_SUCCESS;
+  DYNAMIC_SI_LIBARY_PROTOCOL2     *DynamicSiLibraryProtocol2 = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return TRUE;
+  }
+
+  return DynamicSiLibraryProtocol2->IsSlowBoot ();
+} // IsSlowBoot
+
+/**
+  Save SPD date structure to BDAT
+
+  @param[in,out]   BdatHeaderStructPtr - Pointer to BDAT Structure
+  @param[in]       OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
+  @param[in]       SchemaStartAddress  - Starting address where the SPD data schema will be added
+  @param[in, out]  SchemaIndex         - Current schema index inside the BDAT. Need it to update the schema offsets array.
+  @param[out]      SchemaSpaceUsed     - The numebr bytes were filled
+
+  @retval EFI_SUCCESS  - SPD BDAT scehma created successfully
+  @retval !EFI_SUCCESS - SPD BDAT scehma creation failed
+**/
+EFI_STATUS
+SaveSpdToBdat (
+  IN OUT BDAT_STRUCTURE          *BdatHeaderStructPtr,
+  IN     UINT32                  OffsetFromLastSchema,
+  IN     EFI_PHYSICAL_ADDRESS    *SchemaStartAddress,
+  IN OUT UINT8                   *SchemaIndex,
+  OUT    UINT32                  *SchemaSpaceUsed
+  )
+{
+  EFI_STATUS                        Status                      = EFI_SUCCESS;
+  UINT32                            *SchemaAddrLocationArray    = NULL;
+  UINT32                            SpdDataSize                 = 0;
+  EFI_PHYSICAL_ADDRESS              Address                     = 0;
+  BDAT_SCHEMA_HEADER_STRUCTURE      *SpdSchemaHeaderPtr         = NULL;
+//  UINT16                            *SpdVariableName            = L"SpdData";
+  VOID                              *VariableData               = NULL;
+  BOOLEAN                           SaveToVariable              = TRUE;
+  UINTN                             CompareValue;
+
+  if ((BdatHeaderStructPtr == NULL) || (SchemaStartAddress == NULL) || (SchemaIndex == NULL) || (SchemaSpaceUsed == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Address = *SchemaStartAddress;
+  *SchemaSpaceUsed = 0;
+
+  //
+  // Add SPD schema
+  //
+  DEBUG ((DEBUG_VERBOSE, "\nStarting to add SPD schema  at Address = 0x%x\n", Address));
+
+  //
+  // Update the schema offset arrary
+  //
+  SchemaAddrLocationArray = (UINT32 *)((EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + sizeof(BDAT_STRUCTURE));
+
+  if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) {
+    if (*SchemaIndex == 0) {
+      SchemaAddrLocationArray[*SchemaIndex] = OffsetFromLastSchema;
+    }
+    else {
+      SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + OffsetFromLastSchema;
+    }
+  }
+
+  SpdSchemaHeaderPtr = (BDAT_SCHEMA_HEADER_STRUCTURE *)Address;
+  SpdSchemaHeaderPtr->SchemaId = gSpdBdatSchemaGuid;
+
+  //
+  // CRC16 value of the BDAT_SCHEMA_HEADER_STRUCTURE
+  //
+  SpdSchemaHeaderPtr->Crc16 = 0;
+  Status = CalculateCrc16 (
+    (VOID *)SpdSchemaHeaderPtr,
+    sizeof(BDAT_SCHEMA_HEADER_STRUCTURE),
+    &SpdSchemaHeaderPtr->Crc16
+  );
+
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    SpdSchemaHeaderPtr->Crc16 = 0xFFFF;
+  }
+
+  Address = Address + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
+  *SchemaSpaceUsed = *SchemaSpaceUsed + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
+
+  SpdDataSize = GetSpdDataSize ();
+
+  if (IsSlowBoot ()) {
+    //
+    // Read SPD via Smbus, fill up the SPD data structure.
+    //
+    FillSpdSchema (Address, SpdDataSize);
+
+    //
+    // Save the SPD data structure to EFI variables to save fast boot time
+    //
+    // Before save variable, read and comapre to current data. If they are the same, then
+    // don't save it.
+    // If fail to read the variable(the variable doesn't exist), save variable.
+    //
+
+    SaveToVariable = TRUE;
+
+    VariableData = AllocatePool (SpdDataSize);
+    if (VariableData == NULL) {
+      DEBUG ((DEBUG_ERROR, "Not able to allocate space to store SPD variable data.\n"));
+      Status = EFI_OUT_OF_RESOURCES;
+      goto End;
+    }
+
+//    Status = LoadCompressedVariable (SpdVariableName, gSpdVariableGuid, VariableData, SpdDataSize);
+
+    if (!EFI_ERROR (Status)) {
+      CompareValue = CompareMem ((VOID *)Address, VariableData, SpdDataSize);
+      if (CompareValue == 0) {
+        SaveToVariable = FALSE;
+        DEBUG ((DEBUG_VERBOSE, "No change to the SPD data, don't save variable.\n"));
+      }
+    }
+
+    if (SaveToVariable) {
+//      Status = CompressAndSaveToVariable (SpdVariableName, gSpdVariableGuid, (VOID *)Address, SpdDataSize);
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "Failed to save SPD data to variable.\n"));
+        goto End;
+      }
+
+      DEBUG ((DEBUG_VERBOSE, "Save SPD data to EFI variable.\n"));
+    }
+  } else {
+    //
+    // Fast boot, read the SPD data from vaiable
+    //
+//    Status = LoadCompressedVariable (SpdVariableName, gSpdVariableGuid, (VOID *)Address, SpdDataSize);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Failed to load SPD data from variable.\n"));
+      goto End;
+    }
+    DEBUG ((DEBUG_VERBOSE, "Fill with SPD data from EFI variable.\n"));
+  }
+
+  End:
+
+  if (VariableData != NULL) {
+    FreePool (VariableData);
+  }
+
+  SpdSchemaHeaderPtr->DataSize = SpdDataSize + sizeof (BDAT_SCHEMA_HEADER_STRUCTURE);
+  *SchemaSpaceUsed = *SchemaSpaceUsed + SpdDataSize;
+
+  *SchemaIndex = *SchemaIndex + 1;
+  return Status;
+} //SaveSpdToBdat
+
+/**
+  Save memory training date structure to BDAT
+
+  @param[in,out]   BdatHeaderStructPtr - Pointer to BDAT Structure
+  @param[in]       OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
+  @param[in]       SchemaStartAddress  - Starting address where the memory training data schema will be added
+  @param[in, out]  SchemaIndex         - Current schema index inside the BDAT. Need it to update the schema offsets array.
+  @param[out]      SchemaSpaceUsed     - The numebr bytes were filled
+
+  @retval EFI_SUCCESS  - Memory training data BDAT scehma created successfully
+  @retval !EFI_SUCCESS - Memory training data BDAT scehma creation failed
+**/
+EFI_STATUS
+SaveTrainingDataToBdat (
+  IN OUT BDAT_STRUCTURE          *BdatHeaderStructPtr,
+  IN     UINT32                  OffsetFromLastSchema,
+  IN     EFI_PHYSICAL_ADDRESS    *SchemaStartAddress,
+  IN OUT UINT8                   *SchemaIndex,
+  OUT    UINT32                  *SchemaSpaceUsed
+  )
+{
+  EFI_STATUS                        Status                      = EFI_SUCCESS;
+  UINT32                            *SchemaAddrLocationArray    = NULL;
+  EFI_HOB_GUID_TYPE                 *GuidHob                    = NULL;
+  EFI_PHYSICAL_ADDRESS              Address                     = 0;
+  MEM_TRAINING_DATA_HEADER          *TrainingDataHeader         = NULL;
+  MEM_TRAINING_DATA_HOB_HEADER      *TrainingDataHobHeader      = NULL;
+  EFI_GUID                          TrainingDataGuid            = gMemTrainingDataHobGuid;
+  BDAT_SCHEMA_HEADER_STRUCTURE      *SchemaHeaderPtr            = NULL;
+  INT32                             RemainingDataSize           = 0;
+  UINT32                            HobSize                     = 0;
+  UINT32                            TrainingDataSize            = 0;
+  UINT8                             HobIndex                    = 0;
+
+  if ((BdatHeaderStructPtr == NULL) || (SchemaStartAddress == NULL) || (SchemaIndex == NULL) || (SchemaSpaceUsed == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Address = *SchemaStartAddress;
+  *SchemaSpaceUsed = 0;
+
+  DEBUG ((DEBUG_VERBOSE, "\nStarting to copy memory training data schema at Address = 0x%x\n", Address));
+
+  //
+  // Update the schema offset arrary
+  //
+  SchemaAddrLocationArray = (UINT32 *)((EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + sizeof(BDAT_STRUCTURE));
+
+  if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) {
+    if (*SchemaIndex == 0) {
+      SchemaAddrLocationArray[*SchemaIndex] = OffsetFromLastSchema;
+    }
+    else {
+      SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + OffsetFromLastSchema;
+    }
+  }
+
+  SchemaHeaderPtr = (BDAT_SCHEMA_HEADER_STRUCTURE *)Address;
+  SchemaHeaderPtr->SchemaId = gMemTrainingDataBdatSchemaGuid;
+  *SchemaSpaceUsed = *SchemaSpaceUsed + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
+
+  //
+  // CRC16 value of the BDAT_SCHEMA_HEADER_STRUCTURE
+  //
+  SchemaHeaderPtr->Crc16 = 0;
+  Status = CalculateCrc16 (
+    (VOID *)SchemaHeaderPtr,
+    sizeof(BDAT_SCHEMA_HEADER_STRUCTURE),
+    &SchemaHeaderPtr->Crc16
+  );
+
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    SchemaHeaderPtr->Crc16 = 0xFFFF;
+  }
+
+  GuidHob = GetFirstGuidHob (&TrainingDataGuid);
+
+  ASSERT (GuidHob != NULL);
+  if (GuidHob == NULL) {
+    DEBUG ((DEBUG_ERROR, "Not found training data HOB with GUID:%g\n", &TrainingDataGuid));
+    return EFI_NOT_FOUND;
+  }
+
+  TrainingDataHobHeader = GET_GUID_HOB_DATA (GuidHob);
+  TrainingDataSize = TrainingDataHobHeader->Size - sizeof (MEM_TRAINING_DATA_HOB_HEADER); // This is the size of data to copy to the RT memory.
+
+  TrainingDataHeader = (MEM_TRAINING_DATA_HEADER *)((EFI_PHYSICAL_ADDRESS)TrainingDataHobHeader + sizeof (MEM_TRAINING_DATA_HOB_HEADER));
+
+  HobSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
+  ASSERT (TrainingDataSize <= HobSize);
+
+  HobIndex += 1;
+  DEBUG ((DEBUG_VERBOSE, "Memory training data structre size:%d\n", TrainingDataHeader->Size));
+  SchemaHeaderPtr->DataSize = TrainingDataHeader->Size + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
+
+  //
+  // This is the total data size in the training data structure.
+  //
+  RemainingDataSize = (INT32) TrainingDataHeader->Size;
+
+  DEBUG ((DEBUG_VERBOSE, "Remaining training data:%d\n", RemainingDataSize));
+  //
+  // Copy training data HOBs to RT Memory
+  //
+  Address = Address + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
+  CopyMem ((VOID *)Address, (VOID *)TrainingDataHeader, TrainingDataSize);
+
+  *SchemaSpaceUsed = *SchemaSpaceUsed + TrainingDataSize;
+
+  Address = Address + TrainingDataSize;
+  RemainingDataSize -= TrainingDataSize;
+
+ while (RemainingDataSize > 0) {
+
+    GuidHob = GET_NEXT_HOB (GuidHob); // Increment to next HOB
+    GuidHob = GetNextGuidHob (&TrainingDataGuid, GuidHob);  // Now search for next instance of the BDAT HOB
+
+    ASSERT (GuidHob != NULL);
+    if (GuidHob == NULL) {
+      DEBUG ((DEBUG_ERROR, "Not found training data HOB with GUID:%g\n", &TrainingDataGuid));
+      return EFI_NOT_FOUND;
+    }
+
+    TrainingDataHobHeader = GET_GUID_HOB_DATA (GuidHob);
+    TrainingDataSize = TrainingDataHobHeader->Size - sizeof (MEM_TRAINING_DATA_HOB_HEADER); // This is the size of data to copy to the RT memory.
+
+    HobSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
+    ASSERT (TrainingDataSize <= HobSize);
+
+    HobIndex += 1;
+
+    //
+    // Copy training data HOBs to RT Memory
+    //
+    CopyMem ((VOID *)Address, (VOID *)((EFI_PHYSICAL_ADDRESS)TrainingDataHobHeader + sizeof (MEM_TRAINING_DATA_HOB_HEADER)), TrainingDataSize);
+
+    *SchemaSpaceUsed = *SchemaSpaceUsed + TrainingDataSize;
+
+    Address = Address + TrainingDataSize;
+    RemainingDataSize -= TrainingDataSize;
+    DEBUG ((DEBUG_VERBOSE, "Remaining training data:%d after copying Hob:%d \n", RemainingDataSize, HobIndex));
+  }
+
+  //
+  // Update training data header structure CRC, after all the training data were copied from HOBs to a RT contiguous memory region.
+  //
+  TrainingDataHeader->Crc = 0;
+  TrainingDataHeader->Crc = CalculateCrc32 ((VOID *) TrainingDataHeader, TrainingDataHeader->Size);
+
+  *SchemaIndex = *SchemaIndex + 1;
+
+  return EFI_SUCCESS;
+} //SaveTrainingDataToBdat

+ 673 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibDsdt.c

@@ -0,0 +1,673 @@
+/** @file
+  ACPI Platform Driver Hooks
+
+  @copyright
+  Copyright 1996 - 2020 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include "AcpiPlatformLibLocal.h"
+
+
+#define CPM_MMIO_SIZE           0x100000000         // 4G MMIO resource for CPM
+#define HQM_MMIO_SIZE           0x400000000         // 16G MMIO resource for HQM
+
+extern BIOS_ACPI_PARAM             *mAcpiParameter;
+extern struct SystemMemoryMapHob   *mSystemMemoryMap;
+extern EFI_IIO_UDS_PROTOCOL        *mIioUds;
+extern CPU_CSR_ACCESS_VAR          *mCpuCsrAccessVarPtr;
+
+extern SOCKET_MP_LINK_CONFIGURATION  mSocketMpLinkConfiguration;
+extern SOCKET_IIO_CONFIGURATION     mSocketIioConfiguration;
+extern SOCKET_POWERMANAGEMENT_CONFIGURATION mSocketPowermanagementConfiguration;
+
+extern BOOLEAN      mCpuOrderSorted;
+extern UINT32       mApicIdMap[MAX_SOCKET][MAX_CORE * MAX_THREAD];
+extern UINT32       mNumOfBitShift;
+extern CPU_ID_ORDER_MAP             mCpuApicIdOrderTable[MAX_CPU_NUM];
+
+
+AML_OFFSET_TABLE_ENTRY            *mAmlOffsetTablePointer = NULL;
+
+/**
+    Check current thread status
+
+    @param ApicId - current thread ApicId
+
+    @retval EFI_SUCCESS     Returns Success if current thread is active
+    @retval EFI_UNSUPPORTED Table is not supported
+**/
+EFI_STATUS
+CheckCurrentThreadStatus (
+  UINT32 ApicId
+  )
+{
+  UINT32 Index;
+
+  for (Index = 0; Index < MAX_CPU_NUM; Index++) {
+    if ((mCpuApicIdOrderTable[Index].Flags == 1) && (mCpuApicIdOrderTable[Index].ApicId == ApicId)) {
+      return EFI_SUCCESS;
+    }
+  }
+  return EFI_UNSUPPORTED;
+}
+
+
+/**
+  Get socket, stack and optionaly port index from PCI device path.
+
+  The PCI device path is typically:
+  '_SB_.PCxy.FIXz' for PCIe stack object
+  '_SB_.UCxy.FIXz' for UBOX stack object
+  '_SB_.PCxy.RPya' for PCIe bridge root port object
+  where x and y are hex digits, and 'a' is a letter like 'A', 'B',..,'H'.
+
+  NOTE: 'xy' is decimal number of subsequent PCIe stack, not including UBOX.
+        For UBOX UCxy, 'x' is socket, 'y' is stack.
+
+  @param[in]  DevPathPtr - PCI device path, e.g. '_SB_.PC00.FIX1'
+  @param[out] SocketPtr  - Buffer for socket index.
+  @param[out] StackPtr   - Buffer for stack index.
+  @param[out] PortkPtr   - Buffer for port index.
+**/
+VOID
+AcpiPciDevPath2SktStkPort (
+  IN  CHAR8  *DevPathPtr,
+  OUT UINT8  *SocketPtr,
+  OUT UINT8  *StackPtr,
+  OUT UINT8  *PortPtr
+  )
+{
+  UINT16 SysStackNo;
+  UINT8  SocketNo = 0xFF;
+  UINT8  StackNo = 0xFF;
+  UINT8  PortNo = 0xFF;
+
+  if (PortPtr != NULL) {
+    //
+    // Device path should contain bridge root port object, let's verify.
+    //
+    if (AsciiStrLen (DevPathPtr) < 3*4 + 2 ||
+        DevPathPtr[10]  != 'R' || DevPathPtr[12]  != 'P' || DevPathPtr[13]  < 'A' || DevPathPtr[13]  > 'H') {
+
+      goto ErrExit;
+    }
+    PortNo = DevPathPtr[13] - 'A';
+  }
+  if (AsciiStrLen (DevPathPtr) < 2*4 + 1 || DevPathPtr[7]  < '0' || DevPathPtr[8]  < '0') {
+
+    goto ErrExit;
+  }
+  switch (DevPathPtr[5] << 8 | DevPathPtr[6]) {
+
+    case ('P' << 8 | 'C'):
+      if (DevPathPtr[7] > '9' || DevPathPtr[8] > '9') {
+
+        goto ErrExit;
+      }
+      SysStackNo = (DevPathPtr[7] - '0') * 10;
+      SysStackNo += DevPathPtr[8] - '0';
+      SocketNo = (UINT8)(SysStackNo / MAX_IIO_STACK);
+      StackNo = (UINT8)(SysStackNo % MAX_IIO_STACK);
+      break;
+
+    case ('U' << 8 | 'C'):
+      if (DevPathPtr[7] <= '9') {
+
+        SocketNo = DevPathPtr[7] - '0';
+
+      } else if (DevPathPtr[7] <= 'F') {
+
+        if (DevPathPtr[7] < 'A') {
+
+          goto ErrExit;
+        }
+        SocketNo = 10 + DevPathPtr[7] - 'A';
+
+      } else if (DevPathPtr[7] <= 'f') {
+
+        if (DevPathPtr[7] < 'a') {
+
+          goto ErrExit;
+        }
+        SocketNo = 10 + DevPathPtr[7] - 'a';
+
+      } else {
+        goto ErrExit;
+      }
+      if (DevPathPtr[8] <= '9') {
+
+        StackNo = DevPathPtr[8] - '0';
+
+      } else if (DevPathPtr[8] <= 'F') {
+
+        if (DevPathPtr[8] < 'A') {
+
+          goto ErrExit;
+        }
+        StackNo = 10 + DevPathPtr[8] - 'A';
+
+      } else {
+        goto ErrExit;
+      }
+      break;
+
+    default:
+    ErrExit:
+      DEBUG ((DEBUG_ERROR, "[ACPI] ERROR: String '%a' is not valid PCI stack name, ", DevPathPtr));
+      DEBUG ((DEBUG_ERROR, "expect _SB_.PCxy.FIXz, or _SB_.UCxv.FIXz, or _SB_.PCxy.RPya\n"));
+      break;
+  }
+  if (SocketPtr != NULL) {
+    *SocketPtr = SocketNo;
+  }
+  if (StackPtr != NULL) {
+    *StackPtr = StackNo;
+  }
+  if (PortPtr != NULL) {
+    *PortPtr = PortNo;
+  }
+  return;
+}
+
+
+/**
+  Update the DSDT table
+
+  @param[in,out] *Table   - The table to be set
+
+  @retval EFI_SUCCESS - DSDT updated
+  @retval EFI_INVALID_PARAMETER - DSDT not updated
+**/
+EFI_STATUS
+PatchDsdtTable (
+  IN OUT EFI_ACPI_COMMON_HEADER   *Table
+  )
+{
+  EFI_STATUS Status;
+  UINT8                         *DsdtPointer;
+  UINT32                        *Signature;
+  UINT32                        *Signature2;
+  UINT32                        Fixes;
+  UINT32                        NodeIndex;
+  UINT8                         Counter;
+  UINT16                        i;  // DSDT_PLATEXRP_OffsetTable LUT entries extends beyond 256!
+  UINT8                         BusBase = 0, BusLimit = 0;
+  UINT16                        IoBase  = 0, IoLimit  = 0;
+  UINT32                        MemBase32 = 0, MemLimit32 = 0;
+  UINT64                        MemBase64 = 0, MemLimit64 = 0;
+  AML_RESOURCE_ADDRESS16        *AmlResourceAddress16Pointer;
+  AML_RESOURCE_ADDRESS32        *AmlResourceAddress32Pointer;
+  AML_RESOURCE_ADDRESS64        *AmlResourceAddress64Pointer;
+  EFI_ACPI_DESCRIPTION_HEADER   *TableHeader;
+  UINT32                        AdjustSize = 0;
+  UINT32                        CpuSkt = 0;
+  UINT32                        CpuIndex = 0;
+  ACPI_NAMEPACK_DWORD           *NamePtr;
+  UINT8                         *CurrPtr;
+  UINT8                         *EndPtr;
+  const UINT32                  *ApicMapPtr;
+  UINT8                         Socket;
+  UINT8                         Stack;
+  UINT8                         UboxStack;
+  UINT8                         PropagateSerrOption;
+  UINT8                         PropagatePerrOption;
+
+  Status = GetOptionData (&gEfiSetupVariableGuid, OFFSET_OF(SYSTEM_CONFIGURATION, PropagateSerr), &PropagateSerrOption, sizeof(PropagateSerrOption));
+  if (EFI_ERROR (Status)) {
+    mAcpiParameter->PropagateSerrOption = 1;
+  } else {
+    mAcpiParameter->PropagateSerrOption = PropagateSerrOption;
+  }
+
+  Status = GetOptionData (&gEfiSetupVariableGuid, OFFSET_OF(SYSTEM_CONFIGURATION, PropagatePerr), &PropagatePerrOption, sizeof(PropagatePerrOption));
+  if (EFI_ERROR (Status)) {
+    mAcpiParameter->PropagatePerrOption = 1;
+  } else {
+    mAcpiParameter->PropagatePerrOption = PropagatePerrOption;
+  }
+
+  TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Table;
+
+  if (mAmlOffsetTablePointer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  mAcpiParameter->SocketBitMask = mCpuCsrAccessVarPtr->socketPresentBitMap;
+
+  for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+    if (!mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].Valid) {
+      mAcpiParameter->IioPresentBitMask[Socket] = 0;
+      continue;
+    }
+    mAcpiParameter->IioPresentBitMask[Socket] = mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap;
+    for (Stack = 0; Stack < MAX_LOGIC_IIO_STACK; Stack++) {
+
+      mAcpiParameter->BusBase[Socket][Stack] = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].BusBase;
+      DEBUG ((DEBUG_INFO, "[ACPI](DSDT) [%d.%d] BusBase: 0x%02X\n", Socket, Stack, mAcpiParameter->BusBase[Socket][Stack]));
+    }
+  } // for (Socket...)
+
+  //
+  // Update IIO PCIe Root Port PCIe Capability offset
+  // for 10nm process CPUs with PCIe GEN4/GEN5 controller, PCIe Capability offset is at 0x40
+  //
+  mAcpiParameter->IioPcieRpCapOffset = 0x40;
+
+  //
+  // Initialize TsegSize - 1MB aligned.
+  //
+  Fixes = 0;
+  //
+  // Loop through the AML looking for values that we must fix up.
+  //
+  for (i = 0; mAmlOffsetTablePointer[i].Pathname != 0; i++) {
+    //
+    // Point to offset in DSDT for current item in AmlOffsetTable.
+    //
+    DsdtPointer = (UINT8 *) (TableHeader) + mAmlOffsetTablePointer[i].Offset;
+
+    if (mAmlOffsetTablePointer[i].Opcode == AML_DWORD_PREFIX) {
+      //
+      // If Opcode is 0x0C, then operator is Name() or OperationRegion().
+      // (TableHeader + AmlOffsetTable.Offset) is at offset for value to change.
+      //
+      // The assert below confirms that AML structure matches the offsets table.
+      // If not then patching the AML would just corrupt it and result in OS failure.
+      // If you encounter this assert something went wrong in *.offset.h files
+      // generation. Remove the files and rebuild.
+      //
+      ASSERT (DsdtPointer[-1] == mAmlOffsetTablePointer[i].Opcode);
+      //
+      // AmlOffsetTable.Value has FIX tag, so check that to decide what to modify.
+      //
+      Signature = (UINT32 *) (&mAmlOffsetTablePointer[i].Value);
+      switch (*Signature) {
+        //
+        // Due to iASL compiler change and DSDT patch design change, if these items need support
+        // then the ASI files will need to conform to the format requires for iASL to add the items
+        // to the offset table, and we will need to filter them out when iASL is executed.
+        //
+        // "FIX0" OperationRegion() in Acpi\AcpiTables\Dsdt\CommonPlatform.asi
+        //
+        case (SIGNATURE_32 ('F', 'I', 'X', '0')):
+          *(UINT32*)DsdtPointer = (UINT32)(UINTN)mAcpiParameter;
+          Fixes++;
+          break;
+
+        default:
+          DEBUG ((DEBUG_ERROR, "[ACPI](DSDT) WARNING: Object '%a' with opcode 0x%02X not patched\n",
+                  mAmlOffsetTablePointer[i].Pathname, mAmlOffsetTablePointer[i].Opcode));
+          break;
+      }
+    } else if (mAmlOffsetTablePointer[i].Opcode == AML_INDEX_OP) {
+      //
+      // If Opcode is 0x88, then operator is WORDBusNumber() or WORDIO().
+      // (TableHeader + AmlOffsetTable.Offset) must be cast to AML_RESOURCE_ADDRESS16 to change values.
+      //
+      AmlResourceAddress16Pointer = (AML_RESOURCE_ADDRESS16 *) (DsdtPointer);
+      //
+      // The assert below confirms that AML structure matches the offsets table.
+      // If not then patching the AML would just corrupt it and result in OS failure.
+      // If you encounter this assert something went wrong in *.offset.h files
+      // generation. Remove the files and rebuild.
+      //
+      ASSERT (AmlResourceAddress16Pointer->DescriptorType == mAmlOffsetTablePointer[i].Opcode);
+
+      //
+      // Last 4 chars of AmlOffsetTable.Pathname has FIX tag.
+      //
+      Signature = (UINT32 *) (mAmlOffsetTablePointer[i].Pathname + AsciiStrLen(mAmlOffsetTablePointer[i].Pathname) - 4);
+      Signature2 = (UINT32 *) (mAmlOffsetTablePointer[i].Pathname + AsciiStrLen(mAmlOffsetTablePointer[i].Pathname) - 9);
+      switch (*Signature) {
+        //
+        // "FIX1" BUS resource for PCXX in Acpi\AcpiTables\Dsdt\SysBus.asi and PCXX.asi
+        //
+        case (SIGNATURE_32 ('F', 'I', 'X', '1')):
+          AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL);
+
+          BusBase = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].BusBase;
+          BusLimit = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].BusLimit;
+
+          AmlResourceAddress16Pointer->Granularity = 0;
+          if ((BusLimit > BusBase)) {
+            AmlResourceAddress16Pointer->Minimum = (UINT16) BusBase;
+            AmlResourceAddress16Pointer->Maximum = (UINT16) BusLimit;
+            AmlResourceAddress16Pointer->AddressLength = (UINT16) (BusLimit - BusBase + 1);
+          }
+
+          Fixes++;
+          break;
+
+        //
+        // "FIXB" BUS resource for FpgaKtiXX in Acpi\AcpiTables\Dsdt\FpgaKtiXX.asi
+        //
+        case (SIGNATURE_32 ('F', 'I', 'X', 'B')):
+          break;
+
+        //
+        // "FIX2" IO resource for for PCXX in Acpi\AcpiTables\Dsdt\SysBus.asi and PCXX.asi
+        //
+        case (SIGNATURE_32 ('F', 'I', 'X', '2')):
+          AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL);
+
+          IoBase = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceIoBase;
+          IoLimit = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceIoLimit;
+          if (IoLimit > IoBase) {
+            AmlResourceAddress16Pointer->Minimum = (UINT16) IoBase;
+            AmlResourceAddress16Pointer->Maximum = (UINT16) IoLimit;
+            AmlResourceAddress16Pointer->AddressLength = (UINT16) (IoLimit - IoBase + 1);
+          }
+          AmlResourceAddress16Pointer->Granularity = 0;
+
+          Fixes++;
+          break;
+
+        //
+        // "FIX9" BUS resource for UNXX in Acpi\AcpiTables\Dsdt\Uncore.asi
+        //
+        case (SIGNATURE_32('F', 'I', 'X', '9')) :
+          AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL);
+          UboxStack = UBOX_STACK;
+          BusBase = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[UboxStack].BusBase;
+          BusLimit = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[UboxStack].BusLimit;
+          if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[UboxStack].Personality != TYPE_UBOX ||
+              BusBase > BusLimit) {
+
+            DEBUG ((DEBUG_ERROR, "[ACPI](DSDT) ERROR: Stack [%d.%d] of type %d is not UBOX, '%a' not patched\n",
+                    Socket, UboxStack, mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[UboxStack].Personality,
+                    mAmlOffsetTablePointer[i].Pathname));
+            break;
+          }
+          AmlResourceAddress16Pointer->Granularity = 0;
+          if (Stack & 1) {
+            AmlResourceAddress16Pointer->Minimum = BusLimit;
+            AmlResourceAddress16Pointer->Maximum = BusLimit;
+          } else {
+            AmlResourceAddress16Pointer->Minimum = BusBase;
+            AmlResourceAddress16Pointer->Maximum = BusBase;
+          }
+          AmlResourceAddress16Pointer->AddressLength = 1;
+          mAcpiParameter->BusBase[Socket][Stack] = (UINT8)AmlResourceAddress16Pointer->Minimum;
+          mAcpiParameter->IioPresentBitMask[Socket] |= 1 << Stack;
+          Fixes++;
+          break;
+
+        //
+        // "FIX6" IO resource for PCXX in Acpi\AcpiTables\Dsdt\PCXX.asi
+        //
+        case (SIGNATURE_32 ('F', 'I', 'X', '6')):
+          AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL);
+          AmlResourceAddress16Pointer->Granularity = 0;
+          if ((mSocketMpLinkConfiguration.LegacyVgaSoc == Socket) &&
+              (mSocketMpLinkConfiguration.LegacyVgaStack == Stack)){
+
+            AmlResourceAddress16Pointer->Minimum = (UINT16) 0x03b0;
+            AmlResourceAddress16Pointer->Maximum = (UINT16) 0x03bb;
+            AmlResourceAddress16Pointer->AddressLength = (UINT16) 0x000C;
+          }
+          Fixes++;
+         break;
+
+        //
+        // "FIX7" IO resource for PCXX in Acpi\AcpiTables\Dsdt\PCXX.asi
+        //
+        case (SIGNATURE_32 ('F', 'I', 'X', '7')):
+          AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL);
+          AmlResourceAddress16Pointer->Granularity = 0;
+          if ((mSocketMpLinkConfiguration.LegacyVgaSoc == Socket) &&
+              (mSocketMpLinkConfiguration.LegacyVgaStack == Stack)) {
+
+            AmlResourceAddress16Pointer->Minimum = (UINT16) 0x03c0;
+            AmlResourceAddress16Pointer->Maximum = (UINT16) 0x03df;
+            AmlResourceAddress16Pointer->AddressLength = (UINT16) 0x0020;
+          }
+          Fixes++;
+          break;
+
+        default:
+          DEBUG ((DEBUG_ERROR, "[ACPI](DSDT) WARNING: Object '%a' with opcode 0x%02X not patched\n",
+                  mAmlOffsetTablePointer[i].Pathname, mAmlOffsetTablePointer[i].Opcode));
+          break;
+      }
+    } else if (mAmlOffsetTablePointer[i].Opcode == AML_SIZE_OF_OP) {
+      //
+      // If Opcode is 0x87, then operator is DWORDMemory().
+      // (TableHeader + AmlOffsetTable.Offset) must be cast to AML_RESOURCE_ADDRESS32 to change values.
+      //
+      AmlResourceAddress32Pointer = (AML_RESOURCE_ADDRESS32 *) (DsdtPointer);
+      //
+      // The assert below confirms that AML structure matches the offsets table.
+      // If not then patching the AML would just corrupt it and result in OS failure.
+      // If you encounter this assert something went wrong in *.offset.h files
+      // generation. Remove the files and rebuild.
+      //
+      ASSERT (AmlResourceAddress32Pointer->DescriptorType == mAmlOffsetTablePointer[i].Opcode);
+      //
+      // Last 4 chars of AmlOffsetTable.Pathname has FIX tag.
+      //
+      Signature = (UINT32 *) (mAmlOffsetTablePointer[i].Pathname + AsciiStrLen(mAmlOffsetTablePointer[i].Pathname) - 4);
+      Signature2 = (UINT32 *) (mAmlOffsetTablePointer[i].Pathname + AsciiStrLen(mAmlOffsetTablePointer[i].Pathname) - 9);
+      switch (*Signature) {
+        //
+        // "FIX3" PCI32 resource for PCXX in Acpi\AcpiTables\Dsdt\SysBus.asi and PCXX.asi
+        //
+        case (SIGNATURE_32 ('F', 'I', 'X', '3')):
+          AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL);
+
+          MemBase32 = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceMem32Base;
+          MemLimit32 = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceMem32Limit;
+
+          if (MemLimit32 > MemBase32) {
+            AmlResourceAddress32Pointer->Minimum = (UINT32) MemBase32;
+            AmlResourceAddress32Pointer->Maximum = (UINT32) MemLimit32;
+            AmlResourceAddress32Pointer->AddressLength = (UINT32) (MemLimit32 - MemBase32 + 1);
+          }
+          AmlResourceAddress32Pointer->Granularity = 0;
+
+          Fixes++;
+          break;
+
+        //
+        // "FIX5" IO resource for PCXX in Acpi\AcpiTables\Dsdt\PCXX.asi
+        //
+        case (SIGNATURE_32 ('F', 'I', 'X', '5')):
+          AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL);
+          AmlResourceAddress32Pointer->Granularity = 0;
+          if ((mSocketMpLinkConfiguration.LegacyVgaSoc == Socket) &&
+              (mSocketMpLinkConfiguration.LegacyVgaStack == Stack)) {
+              AmlResourceAddress32Pointer->Minimum = 0x000a0000;
+              AmlResourceAddress32Pointer->Maximum = 0x000bffff;
+              AmlResourceAddress32Pointer->AddressLength = 0x00020000;
+          }
+          Fixes++;
+          break;
+
+        //
+        // "FIXZ" IO resource for FpgaBusXX in Acpi\AcpiTables\Dsdt\FpgaBusXX.asi
+        //
+        case (SIGNATURE_32 ('F', 'I', 'X', 'Z')):
+          break;
+
+        default:
+          DEBUG ((DEBUG_ERROR, "[ACPI](DSDT) WARNING: Object '%a' with opcode 0x%02X not patched\n",
+                  mAmlOffsetTablePointer[i].Pathname, mAmlOffsetTablePointer[i].Opcode));
+          break;
+      }
+    } else if (mAmlOffsetTablePointer[i].Opcode == AML_CREATE_DWORD_FIELD_OP) {
+      //
+      // If Opcode is 0x8A, then operator is QWORDMemory().
+      // (TableHeader + AmlOffsetTable.Offset) must be cast to AML_RESOURCE_ADDRESS64 to change values.
+      //
+      AmlResourceAddress64Pointer = (AML_RESOURCE_ADDRESS64 *) (DsdtPointer);
+      //
+      // The assert below confirms that AML structure matches the offsets table.
+      // If not then patching the AML would just corrupt it and result in OS failure.
+      // If you encounter this assert something went wrong in *.offset.h files
+      // generation. Remove the files and rebuild.
+      //
+      ASSERT (AmlResourceAddress64Pointer->DescriptorType == mAmlOffsetTablePointer[i].Opcode);
+      //
+      // Last 4 chars of AmlOffsetTable.Pathname has FIX tag.
+      //
+      Signature = (UINT32 *) (mAmlOffsetTablePointer[i].Pathname + AsciiStrLen(mAmlOffsetTablePointer[i].Pathname) - 4);
+      Signature2 = (UINT32 *) (mAmlOffsetTablePointer[i].Pathname + AsciiStrLen(mAmlOffsetTablePointer[i].Pathname) - 9);
+      switch (*Signature) {
+        //
+        // "FIX4" PCI64 resource for PCXX in Acpi\AcpiTables\Dsdt\SysBus.asi and PCXX.asi
+        //
+        case (SIGNATURE_32 ('F', 'I', 'X', '4')):
+          if (mSocketIioConfiguration.Pci64BitResourceAllocation) {
+
+            AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL);
+            MemBase64 = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceMem64Base;
+            MemLimit64 = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceMem64Limit;
+            if (MemLimit64 > MemBase64) {
+              AmlResourceAddress64Pointer->Granularity = 0;
+              AmlResourceAddress64Pointer->Minimum = (UINT64) MemBase64;
+              AmlResourceAddress64Pointer->Maximum = (UINT64) MemLimit64;
+              AmlResourceAddress64Pointer->AddressLength = (UINT64) (MemLimit64 - MemBase64 + 1);
+            }
+
+            Fixes++;
+          }
+          break;
+
+        default:
+          DEBUG ((DEBUG_ERROR, "[ACPI](DSDT) WARNING: Object '%a' with opcode 0x%02X not patched\n",
+                  mAmlOffsetTablePointer[i].Pathname, mAmlOffsetTablePointer[i].Opcode));
+          break;
+      }
+    } else {
+      DEBUG ((DEBUG_ERROR, "[ACPI](DSDT) WARNING: Object '%a' with opcode 0x%02X not patched\n",
+              mAmlOffsetTablePointer[i].Pathname, mAmlOffsetTablePointer[i].Opcode));
+    }
+  }
+
+  // CurrPtr = beginning of table
+  //
+  CurrPtr = (UINT8 *) TableHeader;
+
+  // EndPtr = beginning of table + length of table
+  //
+  EndPtr = (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length);
+
+  // Subtract from End Ptr the largest data item we read from table
+  //  so we don't try to access data beyond end of table
+  //
+  EndPtr -= 9;
+
+  for (DsdtPointer = CurrPtr; DsdtPointer <= EndPtr; DsdtPointer++) {
+
+    //
+    // fix CpuMemHp.asi, force no same ASL code string as it...
+    //
+    if ((DsdtPointer[0] == 'C') && (DsdtPointer[6] == 0x4)  && (DsdtPointer[5] == 0x10)) {
+      if (mCpuOrderSorted) {
+        CpuSkt = (UINT32) DsdtPointer[4];
+        AdjustSize = 0;
+        if ((DsdtPointer[1] > '0') && (DsdtPointer[1] <= '9')) {
+          AdjustSize = (UINT32) ((DsdtPointer[1] -'0') * 0x100);
+        } else if ((DsdtPointer[1] >= 'A') && (DsdtPointer[1] <= 'F')) {
+          AdjustSize = (UINT32) ((DsdtPointer[1] -'A' + 10) * 0x100);
+        }
+
+        CpuIndex = AdjustSize;
+
+        AdjustSize = 0;
+        if ((DsdtPointer[2] > '0') && (DsdtPointer[2] <= '9')) {
+          AdjustSize = (UINT32) ((DsdtPointer[2] -'0') * 0x10);
+        } else if ((DsdtPointer[2] >= 'A') && (DsdtPointer[2] <= 'F')) {
+          AdjustSize = (UINT32) ((DsdtPointer[2] -'A' + 10) * 0x10);
+        }
+
+        CpuIndex += AdjustSize;
+
+        AdjustSize = 0;
+        if ((DsdtPointer[3] > '0') && (DsdtPointer[3] <= '9')) {
+          AdjustSize = (UINT32) (DsdtPointer[3] -'0');
+        } else if ((DsdtPointer[3] >= 'A') && (DsdtPointer[3] <= 'F')) {
+          AdjustSize = (UINT32) (DsdtPointer[3] -'A' + 10);
+        }
+
+        CpuIndex += AdjustSize;
+
+        NodeIndex = (UINT32) (CpuSkt << mNumOfBitShift) + mApicIdMap[CpuSkt][CpuIndex] ;
+
+        DsdtPointer[4] = (UINT8) 0xFF;
+        if (((mCpuCsrAccessVarPtr->socketPresentBitMap >> CpuSkt) & BIT0) == 1) {
+          if (CheckCurrentThreadStatus (NodeIndex) == EFI_SUCCESS) {
+            DsdtPointer[4] = (UINT8) (NodeIndex & 0xFF);
+          }
+        }
+
+        //
+        // Update IO Address
+        //
+        *(UINT16 *)(DsdtPointer+5) = (UINT16)(PM_BASE_ADDRESS + 0x10);
+      }
+    }
+
+    for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+
+      if ((mCpuCsrAccessVarPtr->socketPresentBitMap & (BIT0 << Socket)) == 0) {
+        continue;
+      }
+      //
+      // Find APT##socket name
+      //
+      if ((DsdtPointer[0] == 'A') && (DsdtPointer[1] == 'P') && (DsdtPointer[2] == 'T') && (DsdtPointer[3] == '0' + Socket)) {
+        NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (DsdtPointer);
+        ApicMapPtr = mApicIdMap[Socket];
+        if (NamePtr->StartByte != AML_NAME_OP) {
+          continue;
+        }
+
+        Counter = DsdtPointer[8];
+        ASSERT (Counter >= (UINT32) (MAX_THREAD * MAX_CORE));
+        DEBUG ((DEBUG_INFO, "\n::ACPI::  Found 'APT%x'...Counter = DsdtPointer[7] = %x\n\n", Socket, Counter));
+         for (i = 0; i < (MAX_THREAD * MAX_CORE); i++) {
+           DEBUG ((DEBUG_VERBOSE, "Before override, DsdtPointer[%x] = %x,   ", i, DsdtPointer[i+9]));
+           DsdtPointer[i+9] = (UINT8)ApicMapPtr[i];
+           DEBUG ((DEBUG_VERBOSE, "Then override value = %x \n", DsdtPointer[i+9]));
+         }
+      }
+    }
+    //
+    // Fix up _S3
+    //
+    if ((DsdtPointer[0] == '_') && (DsdtPointer[1] == 'S') && (DsdtPointer[2] == '3')) {
+      NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (DsdtPointer);
+      if (NamePtr->StartByte != AML_NAME_OP) {
+        continue;
+      }
+
+      if (!mSocketPowermanagementConfiguration.AcpiS3Enable) {
+        //
+        // S3 disabled
+        //
+        DsdtPointer[0] = 'D';
+      }
+    }
+    //
+    // Fix up _S4
+    //
+    if ((DsdtPointer[0] == '_') && (DsdtPointer[1] == 'S') && (DsdtPointer[2] == '4')) {
+      NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (DsdtPointer);
+      if (NamePtr->StartByte != AML_NAME_OP) {
+        continue;
+      }
+      if (!mSocketPowermanagementConfiguration.AcpiS4Enable) {
+        //
+        // S4 disabled
+        //
+        DsdtPointer[0] = 'D';
+      }
+    }
+  }
+  return EFI_SUCCESS;
+}

+ 75 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibFadt.c

@@ -0,0 +1,75 @@
+/** @file
+  ACPI Platform Driver Hooks
+
+  @copyright
+  Copyright 1996 - 2018 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include "AcpiPlatformLibLocal.h"
+#include <Library/PchPcieRpLib.h>
+
+extern UINT8                 mKBPresent;
+extern UINT8                 mMousePresent;
+extern SOCKET_PROCESSORCORE_CONFIGURATION   mSocketProcessorCoreConfiguration;
+extern SOCKET_POWERMANAGEMENT_CONFIGURATION mSocketPowermanagementConfiguration;
+
+
+EFI_STATUS
+PatchFadtTable (
+   IN OUT   EFI_ACPI_COMMON_HEADER  *Table
+   )
+{
+  UINT16                                    LegacyDevice;
+  EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE *FadtHeader;
+  EFI_STATUS                                Status;
+  UINT8                                     PcieGlobalAspm;
+
+  Status = GetOptionData (&gEfiSocketIioVariableGuid, OFFSET_OF(SOCKET_IIO_CONFIGURATION, PcieGlobalAspm), &PcieGlobalAspm, sizeof(UINT8));
+  if (EFI_ERROR (Status)) {
+    PcieGlobalAspm = 0x2;
+  }
+
+  //
+  // Patch FADT for legacy free
+  //
+  LegacyDevice  = 0;
+  FadtHeader    = (EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE *) Table;
+
+  //
+  // Control of setting ASPM disabled bit in FADT
+  //
+  switch (mSocketPowermanagementConfiguration.NativeAspmEnable) {
+
+  case 0:
+    LegacyDevice |= (1 << 4);
+    break;
+
+  case 1:
+    LegacyDevice &= ~(1 << 4);
+    break;
+
+  case 2:
+    if (PcieGlobalAspm == 0) {
+      LegacyDevice |= (1 << 4);
+    } else {
+      LegacyDevice &= ~(1 << 4);
+    }
+    break;
+
+  default:
+    LegacyDevice &= ~(1 << 4);
+    DEBUG ((DEBUG_ERROR, "\n Native ASPM = %d is not valid (expected values are 0, 1, 2). \n", mSocketPowermanagementConfiguration.NativeAspmEnable ));
+    ASSERT (0);
+    break;
+  }
+
+  FadtHeader->IaPcBootArch = LegacyDevice;
+  FadtHeader->Flags |= (mSocketProcessorCoreConfiguration.ForcePhysicalModeEnable) ? EFI_ACPI_6_2_FORCE_APIC_PHYSICAL_DESTINATION_MODE : 0;
+
+  return EFI_SUCCESS;
+}

+ 1710 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibHmat.c

@@ -0,0 +1,1710 @@
+/** @file
+  ACPI Platform Library HMAT
+
+  @copyright
+  Copyright 2016 - 2020 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include "AcpiPlatformLibLocal.h"
+#include <Library/MemTypeLib.h>
+#include <Protocol/Smbios.h>
+#include <IndustryStandard/SmBios.h>
+
+//
+// The represented latency/bandwidth in 'System Locality Latency and Bandwidth
+// Information Structure' is expressed in multiples of Entry Base Unit.
+// Unit of latency is picoseconds and bandwidth is megabytes per second
+// Below #defines are be base units and values for calcualting the latency/bandwidth
+// For example: read latency of DDRT is 180ns which is 180000 picoseconds.
+// This is expressed as DDRT_LATENCY_BASE_UNIT of 1000 and DDRT_READ_LATENCY of 180
+//
+
+#define MEMORY_LATENCY_BASE_UNIT 100
+#define MEMORY_BANDWIDTH_BASE_UNIT 1
+#define DDR2LMCACHE_LATENCY_BASE_UNIT 100
+#define DDR2LMCACHE_BANDWIDTH_BASE_UNIT 1
+
+#define XSOCKET_LATENCY_BASE_UNIT 100
+#define XSOCKET_BANDWIDTH_BASE_UNIT 1
+
+//
+// DDRT values
+//
+#define DDRT_ACCESS_LATENCY 0
+#define DDRT_1LM_READ_LATENCY 2535
+#define DDRT_2LM_READ_LATENCY 3285
+#define DDRT_1LM_WRITE_LATENCY 2535
+#define DDRT_2LM_WRITE_LATENCY 3285
+#define DDRT_ACCESS_BANDWIDTH 0
+#define DDRT_1LM_READ_BANDWIDTH 4625
+#define DDRT_2LM_READ_BANDWIDTH 4625
+#define DDRT_1LM_WRITE_BANDWIDTH 1375
+#define DDRT_2LM_WRITE_BANDWIDTH 1375
+
+//
+// X-SOCKET values
+//
+#define XSOCKET_DDRT_1LM_ACCESS_LATENCY 0
+#define XSOCKET_DDRT_1LM_READ_LATENCY 3160
+#define XSOCKET_DDRT_1LM_WRITE_LATENCY 3160
+#define XSOCKET_DDRT_1LM_ACCESS_BANDWIDTH 0
+#define XSOCKET_DDRT_1LM_READ_BANDWIDTH 4625
+#define XSOCKET_DDRT_1LM_WRITE_BANDWIDTH 1375
+
+#define XSOCKET_DDRT_2LM_ACCESS_LATENCY 0
+#define XSOCKET_DDRT_2LM_READ_LATENCY 3885
+#define XSOCKET_DDRT_2LM_WRITE_LATENCY 3885
+#define XSOCKET_DDRT_2LM_ACCESS_BANDWIDTH 0
+#define XSOCKET_DDRT_2LM_READ_BANDWIDTH 4625
+#define XSOCKET_DDRT_2LM_WRITE_BANDWIDTH 1375
+
+//
+// DDR values 1LM or flat mode
+//
+#define DDR_ACCESS_LATENCY 0
+#define DDR_READ_LATENCY 760
+#define DDR_WRITE_LATENCY 760
+#define DDR_ACCESS_BANDWIDTH 0
+#define DDR_READ_BANDWIDTH 17900
+#define DDR_WRITE_BANDWIDTH 19100
+
+//
+// X-Socket DDR values 1LM or flat mode
+//
+#define XSOCKET_DDR_ACCESS_LATENCY 0
+#define XSOCKET_DDR_READ_LATENCY 1356
+#define XSOCKET_DDR_WRITE_LATENCY 1356
+#define XSOCKET_DDR_ACCESS_BANDWIDTH 0
+#define XSOCKET_DDR_READ_BANDWIDTH 17900
+#define XSOCKET_DDR_WRITE_BANDWIDTH 19100
+
+//
+// DDR/X-Socket DDR values 2LM when acting as cache
+//
+#define DDR2LMCACHE_ACCESS_LATENCY 0
+#define DDR2LMCACHE_READ_LATENCY 760
+#define DDR2LMCACHE_WRITE_LATENCY 760
+#define DDR2LMCACHE_ACCESS_BANDWIDTH 0
+#define DDR2LMCACHE_READ_BANDWIDTH 17900
+#define DDR2LMCACHE_WRITE_BANDWIDTH 12691
+
+
+extern struct SystemMemoryMapHob    *mSystemMemoryMap;
+extern EFI_IIO_UDS_PROTOCOL         *mIioUds;
+extern SOCKET_MEMORY_CONFIGURATION  mSocketMemoryConfiguration;
+extern CPU_CSR_ACCESS_VAR           *mCpuCsrAccessVarPtr;
+
+UINT8   SkippedEntries = 0;
+
+typedef enum {
+  DDR = 0x00,
+  DDRT,
+  DDR2LMCACHE
+} MemoryType;
+
+
+/**
+  Dump HMAT Header
+
+  @param [in]      HdrPtr       Pointer to HMAT Header
+
+  @retval None
+**/
+VOID
+DumpHeader (
+  EFI_ACPI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_HEADER *HdrPtr
+  )
+{
+  DEBUG ((DEBUG_INFO, "=========== HMAT header ==========\n"));
+  DEBUG ((DEBUG_INFO, " Signature:          %.4a\n",  (CHAR8 *)&HdrPtr->Header.Signature));
+  DEBUG ((DEBUG_INFO, " Length:             %d\n",    HdrPtr->Header.Length));
+  DEBUG ((DEBUG_INFO, " Revision:           %Xh\n",   HdrPtr->Header.Revision));
+  DEBUG ((DEBUG_INFO, " Checksum:           N/A - CHECKSUM ADDED LATER\n"));
+  DEBUG ((DEBUG_INFO, " OemId:              %.6a\n",  HdrPtr->Header.OemId));
+  DEBUG ((DEBUG_INFO, " OemTableId:         %.8a\n",  (CHAR8 *)&HdrPtr->Header.OemTableId));
+  DEBUG ((DEBUG_INFO, " OemRevision:        %Xh\n",   HdrPtr->Header.OemRevision));
+  DEBUG ((DEBUG_INFO, " CreatorId:          %.4a\n",  (CHAR8 *)&HdrPtr->Header.CreatorId));
+  DEBUG ((DEBUG_INFO, " CreatorRevision:    %Xh\n",   HdrPtr->Header.CreatorRevision));
+  DEBUG ((DEBUG_INFO, "==================================\n"));
+  DEBUG ((DEBUG_INFO, "\n"));
+}
+
+/**
+  Dump MSARS Structure
+
+  @param [in]      MsarsPtr       Pointer to MSARS Structure
+
+  @retval None
+**/
+VOID
+DumpMsars (
+  MEMORY_SUBSYSTEM_ADDRESS_RANGE_STRUCTURE *MsarsPtr
+  )
+{
+  DEBUG ((DEBUG_INFO, "=========== MSARS Table =============================\n"));
+  DEBUG ((DEBUG_INFO, " Type:                               %d\n",    MsarsPtr->Type));
+  DEBUG ((DEBUG_INFO, " Length:                             %d\n",    MsarsPtr->Length));
+  DEBUG ((DEBUG_INFO, " ProcessorDomainValid:               %d\n",    MsarsPtr->Flags.Bits.ProcessorDomainValid));
+  DEBUG ((DEBUG_INFO, " MemoryDomainValid:                  %d\n",    MsarsPtr->Flags.Bits.MemoryDomainValid));
+  DEBUG ((DEBUG_INFO, " ReservationHint:                    %d\n",    MsarsPtr->Flags.Bits.ReservationHint));
+  DEBUG ((DEBUG_INFO, " ProcessorProximityDomain:           %Xh\n",   MsarsPtr->ProcessorProximityDomain));
+  DEBUG ((DEBUG_INFO, " MemoryProximityDomain:              %Xh\n",   MsarsPtr->MemoryProximityDomain));
+  DEBUG ((DEBUG_INFO, " SystemPhysicalAddressRangeBase:     %llXh\n", MsarsPtr->AddrBase));
+  DEBUG ((DEBUG_INFO, " SystemPhysicalAddressRangeLength:   %llXh\n", MsarsPtr->AddrLength));
+  DEBUG ((DEBUG_INFO, "=====================================================\n"));
+  DEBUG ((DEBUG_INFO, "\n"));
+}
+
+/**
+  Dump HSCIS Structure
+
+  @param [in]      MscisPtr       Pointer to HSCIS Structure
+
+  @retval None
+**/
+VOID
+DumpMscis (
+  MEMORY_SIDE_CACHE_INFORMATION_STRUCTURE *MscisPtr
+  )
+{
+  UINT8     SmbiosHandleIndex;
+
+  DEBUG ((DEBUG_INFO, "=========== MSCIS Table =============================\n"));
+  DEBUG ((DEBUG_INFO, " Type:                               %d\n",    MscisPtr->Type));
+  DEBUG ((DEBUG_INFO, " Length:                             %d\n",    MscisPtr->Length));
+  DEBUG ((DEBUG_INFO, " MemoryProximityDomain:              %Xh\n",   MscisPtr->MemoryProximityDomain));
+  DEBUG ((DEBUG_INFO, " MemorySideCacheSize:                %llXh\n", MscisPtr->MemorySideCacheSize));
+  DEBUG ((DEBUG_INFO, " TotalCacheLevels:                   %d\n",    MscisPtr->CacheAttributes.Bits.TotalCacheLevels));
+  DEBUG ((DEBUG_INFO, " CacheLevel:                         %d\n",    MscisPtr->CacheAttributes.Bits.CacheLevel));
+  DEBUG ((DEBUG_INFO, " CacheAssociativity:                 %d\n",    MscisPtr->CacheAttributes.Bits.CacheAssociativity));
+  DEBUG ((DEBUG_INFO, " WritePolicy:                        %d\n",    MscisPtr->CacheAttributes.Bits.WritePolicy));
+  DEBUG ((DEBUG_INFO, " CacheLineSize:                      %d\n",    MscisPtr->CacheAttributes.Bits.CacheLineSize));
+  DEBUG ((DEBUG_INFO, " NumSmbiosHandles:                   %d\n",    MscisPtr->NumSmbiosHandles));
+
+  for (SmbiosHandleIndex = 0; SmbiosHandleIndex < MscisPtr->NumSmbiosHandles; SmbiosHandleIndex++) {
+    DEBUG ((DEBUG_INFO, " SmbiosHandle[%d]:                    %xh\n",   SmbiosHandleIndex + 1 ,MscisPtr->SmbiosHandles[SmbiosHandleIndex]));
+  }
+  DEBUG ((DEBUG_INFO, "=====================================================\n"));
+  DEBUG ((DEBUG_INFO, "\n"));
+}
+
+/**
+  Dump LBIS Structure
+
+  @param [in]      LbisPtr        Pointer to LBIS Structure
+
+  @retval None
+**/
+VOID
+DumpLbis (
+  LATENCY_BANDWIDTH_INFO_STRUCTURE *LbisPtr
+  )
+{
+  UINTN Index, Index1;
+  UINT32  *TargetProximityDomainList;
+  UINT16  *Entry;
+
+  DEBUG ((DEBUG_INFO, "=========== MLBIS Table =============================\n"));
+  DEBUG ((DEBUG_INFO, " Type:                               %d\n",    LbisPtr->Type));
+  DEBUG ((DEBUG_INFO, " Length:                             %d\n",    LbisPtr->Length));
+  DEBUG ((DEBUG_INFO, " Flags:                              %d\n",    LbisPtr->Flags));
+  DEBUG ((DEBUG_INFO, " DataType:                           %d\n",    LbisPtr->DataType));
+  DEBUG ((DEBUG_INFO, " InitiatorProximityDomainsNumber:    %d\n",    LbisPtr->InitiatorProximityDomainsNumber));
+  DEBUG ((DEBUG_INFO, " TargetProximityDomainsNumber:       %d\n",    LbisPtr->TargetProximityDomainsNumber));
+  DEBUG ((DEBUG_INFO, " EntryBaseUnit:                      %lXh\n",  LbisPtr->EntryBaseUnit));
+  DEBUG ((DEBUG_INFO, " InitiatorProximityDomainList:\n"));
+
+  for (Index = 0; Index < LbisPtr->InitiatorProximityDomainsNumber; Index++) {
+    DEBUG ((DEBUG_INFO, " %d ",  LbisPtr->InitiatorProximityDomainList[Index]));
+  }
+  TargetProximityDomainList = (UINT32*)&(LbisPtr->InitiatorProximityDomainList[Index]);
+  DEBUG ((DEBUG_INFO, "\n"));
+
+  DEBUG ((DEBUG_INFO, " TargetProximityDomainList:\n"));
+  for (Index = 0; Index < LbisPtr->TargetProximityDomainsNumber; Index++) {
+    DEBUG ((DEBUG_INFO, " %d ",  TargetProximityDomainList[Index]));
+  }
+  Entry = (UINT16*)(TargetProximityDomainList + Index);
+  DEBUG ((DEBUG_INFO, "\n"));
+
+  DEBUG ((DEBUG_INFO, "RelativeDistanceEntry:\n"));
+  for (Index = 0; Index < LbisPtr->InitiatorProximityDomainsNumber; Index++) {
+    for (Index1 = 0; Index1 < LbisPtr->TargetProximityDomainsNumber; Index1++) {
+      DEBUG ((DEBUG_INFO, " %d ",  *(Entry + (Index * LbisPtr->TargetProximityDomainsNumber) + Index1)));
+    }
+    DEBUG ((DEBUG_INFO, "\n"));
+  }
+  DEBUG ((DEBUG_INFO, "\n"));
+  DEBUG ((DEBUG_INFO, "=====================================================\n"));
+  DEBUG ((DEBUG_INFO, "\n"));
+}
+
+
+/**
+  Dump HMAT table
+
+  @param [in]      HmatAcpiTable       Pointer to HMAT table.
+
+  @retval None
+**/
+VOID
+DumpHmat (
+  EFI_ACPI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE *HmatAcpiTable
+  )
+{
+  UINT32  TotalLength = HmatAcpiTable->HmatHeader.Header.Length;
+  UINT8   *Table = (UINT8 *)HmatAcpiTable;
+  UINT32  Length;
+  UINT16  Type;
+
+  DumpHeader (&HmatAcpiTable->HmatHeader);
+  Length = sizeof (EFI_ACPI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_HEADER);
+
+  Table += Length;
+  TotalLength -= Length;
+
+  //
+  // Dump tables
+  //
+  while (TotalLength) {
+    Type = ((MEMORY_SUBSYSTEM_ADDRESS_RANGE_STRUCTURE *)Table)->Type;
+    //
+    // For HBM will need to add LBIS structure
+    //
+    if (Type == MEMORY_SUBSYSTEM_ADDRESS_RANGE_STRUCTURE_TYPE) {
+      DumpMsars ((MEMORY_SUBSYSTEM_ADDRESS_RANGE_STRUCTURE *)Table);
+    } else if (Type == MEMORY_SIDE_CACHE_INFORMATION_STRUCTURE_TYPE)  {
+      DumpMscis ((MEMORY_SIDE_CACHE_INFORMATION_STRUCTURE *)Table);
+    } else {
+      DumpLbis ((LATENCY_BANDWIDTH_INFO_STRUCTURE *)Table);
+    }
+
+    //
+    // Goto next entry
+    //
+    Length = ((MEMORY_SUBSYSTEM_ADDRESS_RANGE_STRUCTURE *)Table)->Length;
+    Table += Length;
+    TotalLength -= Length;
+  }
+}
+
+/**
+  Update SMBIOS handles and number of SMBIOS handles which is related to specified NodeId to MEMORY_DOMAIN_LIST_INFO
+
+  SMBIOS Type 17 handles are formed in sequence order. First handle is S0 C0 D0, Second handle is S0 C0 D1 and so on.
+  So we loop in this order to find the handles of DDR which is part of the specific 2LM cache memory.
+
+  @param [in]  HmatData    Points to HMAT structure
+  @param [in]  NodeId      SMBIOS handles related to this NodeId will be retrieved
+
+  @retval None
+**/
+VOID
+UpdateSmbiosHandles(
+  IN HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE *HmatData,
+  IN UINT32                               NodeId,
+  IN UINT8                                Socket,
+  IN UINT32                               ImcBitMap
+  )
+{
+  EFI_STATUS                          Status;
+  STATIC  EFI_SMBIOS_PROTOCOL         *Smbios = NULL;
+  SMBIOS_TABLE_TYPE17                 *Type17Record;
+  EFI_SMBIOS_TABLE_HEADER             *SmbiosRecord;
+  EFI_SMBIOS_HANDLE                   SmbiosHandle;
+  EFI_SMBIOS_TYPE                     SmbiosType;
+  UINT8                               Loop = 1;
+  UINT8                               SlotsPerImc = MAX_DIMM * MAX_MC_CH;
+  UINT8                               DimmsPerImc = 0;
+
+  Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, &Smbios);
+  if (EFI_ERROR (Status)) {
+    return ;
+  }
+
+  SmbiosHandle  = SMBIOS_HANDLE_PI_RESERVED;
+  SmbiosType    = 17;
+
+  //
+  // Adjust ImcBitMap according to the socket number
+  //
+  if (Socket != 0) {
+    ImcBitMap <<= (Socket * SlotsPerImc);
+  }
+
+  if (!PcdGetBool (PcdHalfWidth)) {
+    DimmsPerImc = SlotsPerImc;
+  } else {
+    DimmsPerImc = SlotsPerImc - 1;
+  }
+
+  do {
+    Status = Smbios->GetNext(Smbios, &SmbiosHandle, &SmbiosType, &SmbiosRecord, NULL);
+    if (!EFI_ERROR (Status) && (SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED)) {
+      Type17Record = (SMBIOS_TABLE_TYPE17 *)SmbiosRecord;
+
+      //
+      // 1) check whether the Memory device of this record is cache capable(ie, 2LM DDR cache) and
+      // 2) this memory handle is to the current looping IMC
+      //
+      if ((Type17Record->TypeDetail.CacheDram) && (ImcBitMap & BIT0)) {
+          HmatData->MemoryDomainList[NodeId].SmbiosHandles[HmatData->MemoryDomainList[NodeId].NumSmbiosHandles] = Type17Record->Hdr.Handle ;
+          HmatData->MemoryDomainList[NodeId].NumSmbiosHandles++;
+      }
+    }
+    //
+    // if loop done for this IMC then move for next
+    //
+    if (Loop % DimmsPerImc == 0) {
+      ImcBitMap >>= 1;
+    }
+    ++Loop;
+  } while (!EFI_ERROR (Status) && (SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED) && (ImcBitMap != 0));
+}
+
+/**
+  Remove slack by moving this substructure lower which removes unused memory.
+
+  @param [in]  SlackSize       Points to cumulative unused memory size
+  @param [in]  Src             Points to memory to move
+  @param [in]  SrcLen          Size of memory to move
+
+  @retval None
+**/
+VOID
+RemoveSlack (
+  IN     UINTN  *SlackSize,
+  IN     VOID   *Src,
+  IN     UINTN  SrcLen
+  )
+{
+  VOID *Dst;
+
+  Dst = (UINT8 *)Src - (*SlackSize);
+  CopyMem (Dst, Src, SrcLen);
+}
+
+/**
+  Calculate the Memory Proximity Domain Number and generate its associate list.
+
+  @param [in, out]  HmatData             Pointer to HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE to be filled
+
+  @retval       None.
+**/
+VOID
+GetMemoryDomains (
+  IN OUT  HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE  *HmatData
+)
+{
+  UINT64  MemorySideCacheSize;
+  UINT32  NodeId;
+  UINT32  LastDomainId = 0;
+  UINT8   Index;
+  UINT8   PrevIndex;
+  UINT8   LastIndex = 0;
+  UINT8   Mc;
+  UINT8   Socket;
+  UINT8   McBitmap[EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS];
+  UINT32  PmemEntry[EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS];
+  UINT64  MemoryAddressStore[EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS];
+  UINT64  MemoryAddress;
+  UINT8   MaxEnabledImc = 0;
+  UINTN   ImcIndex;
+  UINT8   MemSocketBitmap = 0;
+  UINT8   NoMemSocketBitmap;
+  BOOLEAN SkipEntry;
+  BOOLEAN UpdateSmbiosHandle = FALSE;
+
+  EFI_STATUS                  Status = EFI_SUCCESS;
+  DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return;
+  }
+
+  HmatData->MemoryDomainNumber = 0;
+
+  ZeroMem (McBitmap, sizeof(McBitmap));
+  ZeroMem (MemoryAddressStore, sizeof(MemoryAddressStore));
+
+  //
+  // Memory Proximity Domain must match the Domain in the SRAT Memory Affinity structure
+  //
+  for (Index = 0; Index < mSystemMemoryMap->numberEntries; Index++) {
+    //
+    // Skip any memory region marked reserved
+    //
+    if (DynamicSiLibraryProtocol2->IsMemTypeReserved (mSystemMemoryMap->Element[Index].Type)) {
+      continue;
+    }
+
+    if (!DynamicSiLibraryProtocol2->IsMemTypeVolatile (mSystemMemoryMap->Element[Index].Type)) {
+      //
+      // Skip all non volatile regions
+      //
+      PmemEntry[SkippedEntries] = Index;
+      SkippedEntries++;
+      continue;
+    }
+
+    SkipEntry = FALSE;
+
+    MemoryAddress = LShiftU64 (mSystemMemoryMap->Element[Index].BaseAddress, MEM_ADDR_SHFT_VAL);
+
+    //
+    // Skip duplicate entries
+    //
+    if (Index) {
+      for (PrevIndex = 0; PrevIndex < Index; PrevIndex++) {
+        if (MemoryAddress == MemoryAddressStore[PrevIndex]) {
+          SkipEntry = TRUE;
+          break;
+        }
+      }
+    }
+    if (SkipEntry) {
+      continue;
+    }
+
+    MemoryAddressStore[Index] = MemoryAddress;
+    LastIndex = Index;
+
+    for (ImcIndex = 0, MaxEnabledImc = 0; ImcIndex < MAX_IMC; ImcIndex++) {
+      if (mSystemMemoryMap->Socket[mSystemMemoryMap->Element[Index].SocketId].imcEnabled[ImcIndex] != 0) {
+        MaxEnabledImc ++;
+      }
+    }
+
+    //
+    // Update bitmap for sockets with memory populated
+    //
+    MemSocketBitmap |= BIT0 << mSystemMemoryMap->Element[Index].SocketId;
+
+    //
+    // Get memory domain (must match SRAT memory domain)
+    //
+    NodeId = ProximityDomainOf (
+                mSystemMemoryMap->Element[Index].SocketId,
+                mSystemMemoryMap->Element[Index].Type,
+                MaxEnabledImc,
+                HmatData->SncEnabled,
+                HmatData->SncNumOfCluster,
+                mSystemMemoryMap->Element[Index].ImcInterBitmap,
+                mSystemMemoryMap->volMemMode,
+                LastDomainId
+                );
+
+    NodeId = (NodeId * HmatData->VirtualNumOfCluster) + (Index % HmatData->VirtualNumOfCluster);
+
+    if (LastDomainId < NodeId) {
+      LastDomainId = NodeId;
+    }
+
+    if (NodeId >= EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS) {
+      DEBUG ((DEBUG_ERROR, "[ACPI] (HMAT) ERROR: Invalid Memory Proximity Domain (0x%x)\n", NodeId));
+      ASSERT (FALSE);
+    }
+
+    //
+    // Update map of indexes included in this memory domain
+    //
+    HmatData->MemoryDomainList[NodeId].MemMapIndexMap |= LShiftU64 (BIT0, Index);
+
+    //
+    // Update Memory domain count and set domain to valid
+    // Prevent counting repeated entries with the same Proximity Domain ID
+    //
+    if ((Index == 0) || (HmatData->MemoryDomainList[NodeId].Valid == 0)) {
+      HmatData->MemoryDomainNumber++;
+      HmatData->MemoryDomainList[NodeId].PhysicalSocketId = mSystemMemoryMap->Element[Index].SocketId;
+      HmatData->MemoryDomainList[NodeId].Valid = 1;
+      McBitmap[NodeId] = 0;
+    }
+
+    if (HmatData->MemoryDomainList[NodeId].Valid) {
+      if (mSystemMemoryMap->Element[Index].Type == MemType2lmDdrCacheMemoryMode) {
+        //
+        // Set up side cache info for 2LM
+        //
+        HmatData->MemoryDomainList[NodeId].Cacheable = 1;
+
+        //
+        // Calculate MemorySideCacheSize
+        // MemorySideCacheSize for each MC is the DDR4 memSize
+        //
+        MemorySideCacheSize = 0;
+        UpdateSmbiosHandle = FALSE;
+
+        for (Mc = 0; Mc < MAX_IMC; Mc++) {
+          if ((mSystemMemoryMap->Element[Index].ImcInterBitmap & (BIT0 << Mc)) && !(McBitmap[NodeId] & (BIT0 << Mc))) {
+            UpdateSmbiosHandle = TRUE;
+            if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_2LM) {
+              MemorySideCacheSize += mSystemMemoryMap->Socket[mSystemMemoryMap->Element[Index].SocketId].imc[Mc].MemSize;
+            } else{ // VOL_MEM_MODE_MIX_1LM2LM
+              MemorySideCacheSize += mSystemMemoryMap->DdrCacheSize[mSystemMemoryMap->Element[Index].SocketId][Mc];
+            }
+          }
+        }
+
+        if (UpdateSmbiosHandle) {
+          UpdateSmbiosHandles (
+            HmatData,
+            NodeId,
+            mSystemMemoryMap->Element[Index].SocketId,
+            mSystemMemoryMap->Element[Index].ImcInterBitmap
+            );
+        }
+        HmatData->MemoryDomainList[NodeId].MemorySideCacheSize += MemorySideCacheSize;
+      }
+      McBitmap[NodeId] |= mSystemMemoryMap->Element[Index].ImcInterBitmap;
+    }
+
+    DEBUG ((DEBUG_INFO, "MemoryDomainList[%x] Valid = %x Cacheable = %x MemorySideCacheSize = %x\n",
+      NodeId,
+      HmatData->MemoryDomainList[NodeId].Valid,
+      HmatData->MemoryDomainList[NodeId].Cacheable,
+      HmatData->MemoryDomainList[NodeId].MemorySideCacheSize
+      ));
+  }
+
+  //
+  // Update LastDomainId for enabled sockets with no memory
+  //
+  NoMemSocketBitmap = mCpuCsrAccessVarPtr->socketPresentBitMap & ~MemSocketBitmap;
+  for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+    if ((BIT0 << Socket) & NoMemSocketBitmap) {
+      LastDomainId += HmatData->SncNumOfCluster;
+    }
+  }
+
+  //
+  // Add skipped entries
+  //
+  for (Index = 0; Index < SkippedEntries; Index++) {
+    SkipEntry = FALSE;
+    MemoryAddress = LShiftU64 (mSystemMemoryMap->Element[PmemEntry[Index]].BaseAddress, MEM_ADDR_SHFT_VAL);
+
+    //
+    // Skip duplicate entries
+    //
+    for (PrevIndex = 0; PrevIndex < LastIndex; PrevIndex++) {
+      if (MemoryAddress == MemoryAddressStore[PrevIndex]) {
+        SkipEntry = TRUE;
+        break;
+      }
+    }
+    if (SkipEntry) {
+      continue;
+    }
+
+    MemoryAddressStore[LastIndex++] = MemoryAddress;
+
+    //
+    // Get memory domain (must match SRAT memory domain)
+    //
+    NodeId = ProximityDomainOf (
+                mSystemMemoryMap->Element[PmemEntry[Index]].SocketId,
+                mSystemMemoryMap->Element[PmemEntry[Index]].Type,
+                MaxEnabledImc,
+                HmatData->SncEnabled,
+                HmatData->SncNumOfCluster,
+                mSystemMemoryMap->Element[PmemEntry[Index]].ImcInterBitmap,
+                mSystemMemoryMap->volMemMode,
+                LastDomainId
+                );
+    NodeId = (NodeId * HmatData->VirtualNumOfCluster) + (Index % HmatData->VirtualNumOfCluster);
+
+    if (LastDomainId < NodeId) {
+      LastDomainId = NodeId;
+    }
+
+    if (NodeId >= EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS) {
+      DEBUG ((DEBUG_ERROR, "[ACPI] (HMAT) ERROR: Invalid Memory Proximity Domain (0x%x)\n", NodeId));
+      ASSERT (FALSE);
+    }
+
+    //
+    // Update map of indexes included in this memory domain
+    //
+    HmatData->MemoryDomainList[NodeId].MemMapIndexMap |= LShiftU64 (BIT0, PmemEntry[Index]);
+
+    //
+    // Update Memory domain count and set domain to valid
+    // Prevent counting repeated entries with the same Proximity Domain ID
+    //
+    if ((PmemEntry[Index] == 0) || (HmatData->MemoryDomainList[NodeId].Valid == 0)) {
+      HmatData->MemoryDomainNumber++;
+      HmatData->MemoryDomainList[NodeId].PhysicalSocketId = mSystemMemoryMap->Element[PmemEntry[Index]].SocketId;
+      HmatData->MemoryDomainList[NodeId].Valid = 1;
+    }
+
+    DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) MemoryDomainList[%x] Valid = %x Cacheable = %x MemorySideCacheSize = %x\n",
+      NodeId,
+      HmatData->MemoryDomainList[NodeId].Valid,
+      HmatData->MemoryDomainList[NodeId].Cacheable,
+      HmatData->MemoryDomainList[NodeId].MemorySideCacheSize
+      ));
+  }
+}
+
+/**
+  Calculate the Processor Proximity Domain Number and generate its associate list.
+
+  @param [in, out]  HmatData             Pointer to HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE to be filled
+
+  @retval       None.
+**/
+VOID
+GetProcessorDomains (
+  IN OUT  HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE  *HmatData
+  )
+{
+  UINT32  NodeId;
+  UINT8   Index;
+  INTN    FirstImc;
+  UINT8   SocketId;
+  UINT8   SocketLogicalId;
+  UINT8   MemSocketBitmap;
+  UINT8   NoMemSocketBitmap;
+
+  EFI_STATUS                  Status = EFI_SUCCESS;
+  DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return;
+  }
+
+  MemSocketBitmap = 0;
+  NoMemSocketBitmap = 0;
+  HmatData->ProcessorDomainNumber = 0;
+
+  //
+  // Processor Proximity Domain must match the Domain in the SRAT APIC or X2APIC Affinity Structure
+  //
+  for (Index = 0; Index < mSystemMemoryMap->numberEntries; Index++) {
+    //
+    // Skip any memory region marked reserved or FPGA
+    //
+    if (DynamicSiLibraryProtocol2->IsMemTypeReserved (mSystemMemoryMap->Element[Index].Type) || DynamicSiLibraryProtocol2->IsMemTypeFpga (mSystemMemoryMap->Element[Index].Type)) {
+      continue;
+    }
+
+    SocketId = mSystemMemoryMap->Element[Index].SocketId;
+    SocketLogicalId = GetSocketLogicalId (SocketId);
+
+    //
+    // Get processor proximity domain
+    //
+    if (HmatData->SncEnabled || HmatData->VirtualNumaEnabled) {
+      FirstImc = LowBitSet32 (mSystemMemoryMap->Element[Index].ImcInterBitmap);
+      if (FirstImc == -1) {
+        FirstImc = 0;
+      }
+      //
+      // Find the 1st IMC according the interbitmap
+      //
+      if (MAX_IMC <= HmatData->SncNumOfCluster) {
+        NodeId = (SocketLogicalId * HmatData->SncNumOfCluster) + (UINT32)FirstImc;
+      } else {
+        NodeId = (SocketLogicalId * HmatData->SncNumOfCluster) + ((UINT32)FirstImc) / HmatData->SncNumOfCluster;
+      }
+
+      NodeId = (NodeId * HmatData->VirtualNumOfCluster) + (Index % HmatData->VirtualNumOfCluster);
+
+      DEBUG ((DEBUG_INFO, "%a: SocketId: 0x%x SncNumOfCluster: 0x%x ImcInterBitmap:0x%x and  NodeId:0x%x\n",
+          __FUNCTION__, mSystemMemoryMap->Element[Index].SocketId, HmatData->SncNumOfCluster, mSystemMemoryMap->Element[Index].ImcInterBitmap, NodeId));
+    } else {
+      NodeId = SocketLogicalId;
+    }
+
+    if (NodeId >= EFI_ACPI_HMAT_NUMBER_OF_PROCESSOR_DOMAINS) {
+      DEBUG ((DEBUG_ERROR, "[ACPI] (HMAT) ERROR: Invalid Processor Proximity Domain (0x%x)\n", NodeId));
+      return;
+    }
+
+    //
+    // Update processor domain count and set domain to valid
+    // Prevent counting repeated entries with the same Proximity Domain ID
+    //
+    if ((Index == 0) || (HmatData->ProcessorDomainList[NodeId] == 0)) {
+      HmatData->ProcessorDomainNumber++;
+      HmatData->ProcessorDomainSocketIdList[NodeId] = SocketId;
+      HmatData->ProcessorDomainList[NodeId] = 1; // Domain is valid
+      MemSocketBitmap |= (BIT0 << mSystemMemoryMap->Element[Index].SocketId);
+    }
+
+    DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) ProcessorDomainList[%x] Valid = %x\n", NodeId, HmatData->ProcessorDomainList[NodeId]));
+  }
+
+  //
+  // Update processor domain for enabled sockets without memory
+  //
+  NoMemSocketBitmap = mCpuCsrAccessVarPtr->socketPresentBitMap & ~MemSocketBitmap;
+  for (SocketId = 0; SocketId < MAX_SOCKET; SocketId++) {
+    if ((BIT0 << SocketId) & NoMemSocketBitmap) {
+      for (Index = 0; Index < (HmatData->SncNumOfCluster * HmatData->VirtualNumOfCluster); Index++) {
+        NodeId = GetSocketLogicalId (SocketId) * HmatData->SncNumOfCluster * HmatData->VirtualNumOfCluster + Index;
+        HmatData->ProcessorDomainNumber++;
+        HmatData->ProcessorDomainSocketIdList[NodeId] = SocketId;
+        HmatData->ProcessorDomainList[NodeId] = 1;
+      }
+    }
+  }
+}
+
+/**
+  Initialize HMAT Data to be consumed when populating tables.
+  This Functions allocates buffer for HMAT Data, so it is caller responsibility to free it.
+
+  @param            None.
+
+  @retval           Pointer to allocated HMAT Data if it was initialized correctly.
+  @retval           NULL if not allocated and not initialized correctly.
+**/
+UINTN *
+InitializeHmatData (
+  VOID
+)
+{
+  HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE  *HmatData = NULL;
+
+  HmatData = AllocateZeroPool (sizeof (HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE));
+  if (HmatData == NULL) {
+    DEBUG ((DEBUG_ERROR, "[ACPI] (HMAT) ERROR: Could not allocate HmatData structure pointer\n"));
+    return (UINTN *) HmatData;
+  }
+
+  if (mIioUds->IioUdsPtr->SystemStatus.OutSncEn) {
+    HmatData->SncEnabled = 1;
+    HmatData->SncNumOfCluster = mIioUds->IioUdsPtr->SystemStatus.OutNumOfCluster;
+  } else {
+    HmatData->SncNumOfCluster = 1;
+  }
+
+  if (mSystemMemoryMap->VirtualNumaEnable) {
+    HmatData->VirtualNumaEnabled = 1;
+    HmatData->VirtualNumOfCluster = mSystemMemoryMap->VirtualNumOfCluster;
+  } else {
+    HmatData->VirtualNumOfCluster = 1;
+  }
+
+  GetProcessorDomains (HmatData);
+  GetMemoryDomains (HmatData);
+
+  return (UINTN *)HmatData;
+}
+
+/**
+  Patch HMAT MSARS substructure.
+
+  @param [in, out]  HmatAcpiTable   Points to HMAT table to be modified
+  @param [in, out]  SlackSize       Points to cumulative slack size
+  @param [in]       HmatData        HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE to be consumed
+
+  @retval None
+**/
+VOID
+PatchHmatMsars (
+  IN OUT EFI_ACPI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE  *HmatAcpiTable,
+  IN OUT UINTN                                          *SlackSize,
+  IN     HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE           *HmatData
+  )
+{
+  UINT32  Index;
+  UINT32  PrevIndex;
+  UINT32  MemoryNodeId;
+  UINT32  ProcessorNodeId;
+  UINT32  Count = 0;
+  UINT32  UnusedCount;
+  UINT8   MemoryNodeValid;
+  UINT16  ProcessorNodeValid;
+  UINT64  MemoryAddress;
+  BOOLEAN SkipEntry;
+  INTN    FirstImc;
+  UINT8   SocketLogicalId;
+
+  EFI_STATUS                  Status = EFI_SUCCESS;
+  DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return;
+  }
+
+
+  DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) Populating Memory Subsystem Address Range Structure\n"));
+  for (Index = 0; Index < mSystemMemoryMap->numberEntries; Index++) {
+    //
+    // Skip any memory region marked reserved
+    //
+    DEBUG ((DEBUG_INFO, "[ACPI] mSystemMemoryMap->Element[%d].Type = 0x%x\n",Index, mSystemMemoryMap->Element[Index].Type));
+    if (DynamicSiLibraryProtocol2->IsMemTypeReserved (mSystemMemoryMap->Element[Index].Type)) {
+      continue;
+    }
+
+    if (Count >= EFI_ACPI_HMAT_MSARS_COUNT) {
+      DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) Invalid MSARS entry with Index = 0x%x\n", Count));
+      ASSERT (FALSE);
+      break;
+    }
+
+    SkipEntry = FALSE;
+
+    //
+    // Skip duplicate entries
+    //
+    MemoryAddress = LShiftU64 (mSystemMemoryMap->Element[Index].BaseAddress, MEM_ADDR_SHFT_VAL);
+    if (Count) {
+      for (PrevIndex = 0; PrevIndex < Count; PrevIndex++) {
+        if (MemoryAddress == HmatAcpiTable->Msars[PrevIndex].AddrBase) {
+          SkipEntry = TRUE;
+          break;
+        }
+      }
+    }
+    if (SkipEntry) {
+      continue;
+    }
+
+    //
+    // Find memory domain for this index
+    //
+    for (MemoryNodeId = 0; MemoryNodeId < EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS; MemoryNodeId++) {
+      if (HmatData->MemoryDomainList[MemoryNodeId].MemMapIndexMap & LShiftU64(BIT0, Index)) {
+        break;
+      }
+    }
+
+    //
+    // Fill in valid field
+    //
+    if (MemoryNodeId < EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS) {
+      MemoryNodeValid = HmatData->MemoryDomainList[MemoryNodeId].Valid;
+    } else {
+      MemoryNodeValid = 0;
+    }
+
+    //
+    // Get processor domain for this index
+    //
+    if (DynamicSiLibraryProtocol2->IsMemTypeFpga (mSystemMemoryMap->Element[Index].Type)) {
+      ProcessorNodeValid = 0;  // There is no processor for FPGA.
+      ProcessorNodeId = 0;     // This field will be ingored for FPGA.
+    } else {
+      SocketLogicalId = GetSocketLogicalId (mSystemMemoryMap->Element[Index].SocketId);
+      if (HmatData->SncEnabled || HmatData->VirtualNumaEnabled) {
+        FirstImc = LowBitSet32 (mSystemMemoryMap->Element[Index].ImcInterBitmap);
+        if (FirstImc == -1) {
+          FirstImc = 0;
+        }
+        //
+        // Find the 1st IMC according the interbitmap
+        //
+        if (MAX_IMC <= HmatData->SncNumOfCluster) {
+          ProcessorNodeId = (SocketLogicalId * HmatData->SncNumOfCluster) + (UINT32)FirstImc;
+        } else {
+          ProcessorNodeId = (SocketLogicalId * HmatData->SncNumOfCluster) + ((UINT32)FirstImc) / HmatData->SncNumOfCluster;
+        }
+        ProcessorNodeId = (ProcessorNodeId * HmatData->VirtualNumOfCluster) + (Index % HmatData->VirtualNumOfCluster);
+        DEBUG ((DEBUG_INFO, "%a: SocketId: 0x%x SncNumOfCluster: 0x%x ImcInterBitmap:0x%x and  NodeId:0x%x \n",
+          __FUNCTION__, mSystemMemoryMap->Element[Index].SocketId, HmatData->SncNumOfCluster, mSystemMemoryMap->Element[Index].ImcInterBitmap, ProcessorNodeId));
+      } else {
+        ProcessorNodeId = SocketLogicalId;
+      }
+
+      //
+      // Fill in valid field
+      //
+      if (ProcessorNodeId < EFI_ACPI_HMAT_NUMBER_OF_PROCESSOR_DOMAINS) {
+        ProcessorNodeValid = HmatData->ProcessorDomainList[ProcessorNodeId];
+      } else {
+        ProcessorNodeValid = 0;
+      }
+    }
+
+    //
+    // The HOB has base addr in 64 MB chunks
+    //
+    HmatAcpiTable->Msars[Count].AddrBase  = MemoryAddress;
+    HmatAcpiTable->Msars[Count].AddrLength = LShiftU64 (mSystemMemoryMap->Element[Index].ElementSize, MEM_ADDR_SHFT_VAL);
+
+    HmatAcpiTable->Msars[Count].Flags.Value = 0;
+
+    //
+    // Fill in Proximity Domains
+    //
+    HmatAcpiTable->Msars[Count].ProcessorProximityDomain = ProcessorNodeId;
+    HmatAcpiTable->Msars[Count].Flags.Bits.ProcessorDomainValid = ProcessorNodeValid;
+    HmatAcpiTable->Msars[Count].MemoryProximityDomain = MemoryNodeId;
+    HmatAcpiTable->Msars[Count].Flags.Bits.MemoryDomainValid = MemoryNodeValid;
+
+    DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) MSARS[%x] AddrBase = 0x%lx, AddrLength = 0x%lx, MemDomain = %x, ProcDomain = %x\n",
+      Count,
+      HmatAcpiTable->Msars[Count].AddrBase,
+      HmatAcpiTable->Msars[Count].AddrLength,
+      MemoryNodeId,
+      ProcessorNodeId
+      ));
+    Count++;
+  }
+
+  //
+  // Update SlackSize for unused MSARS entries
+  //
+  UnusedCount = EFI_ACPI_HMAT_MSARS_COUNT - Count;
+  *SlackSize += UnusedCount * sizeof(HmatAcpiTable->Msars[0]);
+}
+
+/**
+  Prints HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE for debug purposes.
+
+  @param [in]       Lbis        Points to HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE to be printed.
+
+  @retval None.
+**/
+VOID
+PrintLbisHmat (
+  IN     LATENCY_BANDWIDTH_INFO_STRUCTURE  *Lbis
+  )
+{
+  UINT32  Row = 0;
+  UINT32  Col = 0;
+  UINT32  RowBaseIndex = 0;
+  UINT16  *Entry;
+
+  Entry = (UINT16 *) Lbis->RelativeDistanceEntry;
+  DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) SLLBIS Data: "));
+  DEBUG ((DEBUG_INFO, "InitiatorNumber = %d, TargetNumber = %d. ", Lbis->InitiatorProximityDomainsNumber, Lbis->TargetProximityDomainsNumber));
+  DEBUG ((DEBUG_INFO, "Entry Base Unit = %d \n", Lbis->EntryBaseUnit));
+
+  DEBUG ((DEBUG_INFO, "    "));
+  for (Col = 0; Col < Lbis->TargetProximityDomainsNumber; Col++) {
+    DEBUG ((DEBUG_INFO, "%02d        ", Lbis->TargetProximityDomainList[Col]));
+  }
+  DEBUG ((DEBUG_INFO, "\n"));
+  for (Row = 0; Row < Lbis->InitiatorProximityDomainsNumber; Row++) {
+    RowBaseIndex = Row * Lbis->TargetProximityDomainsNumber;
+    DEBUG ((DEBUG_INFO, "%02d  ", Lbis->InitiatorProximityDomainList[Row]));
+    for (Col = 0; Col < Lbis->TargetProximityDomainsNumber; Col++) {
+      DEBUG ((DEBUG_INFO, "%08d  ", Entry[RowBaseIndex + Col]));
+    }
+    DEBUG ((DEBUG_INFO, "\n"));
+  }
+}
+
+/**
+  Get the Read/Write/Access bandwidth value of the memory type.
+
+  @param [in]       DataType         Type of bandwidth value that is required. (Read/Write/Access)
+  @param [in]       Type             Type of memory for which Bandwidth is required. (DDR/DDRT)
+
+  @retval Value of the bandwidth associated with memory type.
+  @retval 0xFF   Input parameters are invalid.
+**/
+
+UINT16
+GetMemoryBandWidth (
+  IN     UINT8                                 DataType,
+  IN     MemoryType                            Type,
+  IN     UINT8                                 volMemMode
+  )
+{
+  if (Type == DDRT) {  // MemoryType == DDRT
+    switch (DataType) {
+      case EFI_ACPI_HMAT_ACCESS_BANDWIDTH :
+        return DDRT_ACCESS_BANDWIDTH;
+      case EFI_ACPI_HMAT_READ_BANDWIDTH :
+        if (volMemMode == VOL_MEM_MODE_1LM) {
+          return DDRT_1LM_READ_BANDWIDTH;
+        } else {
+          return DDRT_2LM_READ_BANDWIDTH;
+        }
+      case EFI_ACPI_HMAT_WRITE_BANDWIDTH :
+        if (volMemMode == VOL_MEM_MODE_1LM) {
+          return DDRT_1LM_WRITE_BANDWIDTH;
+        } else {
+          return DDRT_2LM_WRITE_BANDWIDTH;
+        }
+      default:
+        return 0xFF;
+    }
+  } else if (Type == DDR2LMCACHE) {
+    switch (DataType) {
+      case EFI_ACPI_HMAT_ACCESS_BANDWIDTH :
+        return DDR2LMCACHE_ACCESS_BANDWIDTH;
+      case EFI_ACPI_HMAT_READ_BANDWIDTH :
+        return DDR2LMCACHE_READ_BANDWIDTH;
+      case EFI_ACPI_HMAT_WRITE_BANDWIDTH :
+        return DDR2LMCACHE_WRITE_BANDWIDTH;
+      default:
+        return 0xFF;
+    }
+  } else {
+    switch (DataType) {
+      case EFI_ACPI_HMAT_ACCESS_BANDWIDTH :
+        return DDR_ACCESS_BANDWIDTH;
+      case EFI_ACPI_HMAT_READ_BANDWIDTH :
+        return DDR_READ_BANDWIDTH;
+      case EFI_ACPI_HMAT_WRITE_BANDWIDTH :
+        return DDR_WRITE_BANDWIDTH;
+      default:
+        return 0xFF;
+    }
+  }
+}
+
+/**
+  Get the Read/Write/Access bandwidth value of the memory type across sockets.
+
+  @param [in]       DataType         Type of bandwidth value that is required. (Read/Write/Access)
+  @param [in]       Type             Type of memory for which Bandwidth is required. (DDR/DDRT)
+
+  @retval Value of the bandwidth associated with memory type.
+  @retval 0xFF   Input parameters are invalid.
+**/
+UINT16
+GetXSocketMemoryBandWidth (
+  IN     UINT8                                 DataType,
+  IN     MemoryType                            Type,
+  IN     UINT8                                 volMemMode
+)
+{
+  if (Type == DDRT) {  // MemoryType == DDRT
+    switch (DataType) {
+      case EFI_ACPI_HMAT_ACCESS_BANDWIDTH:
+        return DDRT_ACCESS_BANDWIDTH;
+      case EFI_ACPI_HMAT_READ_BANDWIDTH:
+        if (volMemMode == VOL_MEM_MODE_1LM) {
+          return XSOCKET_DDRT_1LM_READ_BANDWIDTH;
+        } else {
+          return XSOCKET_DDRT_2LM_READ_BANDWIDTH;
+        }
+      case EFI_ACPI_HMAT_WRITE_BANDWIDTH:
+        if (volMemMode == VOL_MEM_MODE_1LM) {
+          return XSOCKET_DDRT_1LM_WRITE_BANDWIDTH;
+        } else {
+          return XSOCKET_DDRT_2LM_WRITE_BANDWIDTH;
+        }
+      default:
+        return 0xFF;
+    }
+  } else if (Type == DDR2LMCACHE) {
+    switch (DataType) {
+      case EFI_ACPI_HMAT_ACCESS_BANDWIDTH:
+        return DDR2LMCACHE_ACCESS_BANDWIDTH;
+      case EFI_ACPI_HMAT_READ_BANDWIDTH:
+        return DDR2LMCACHE_READ_BANDWIDTH;
+      case EFI_ACPI_HMAT_WRITE_BANDWIDTH:
+        return DDR2LMCACHE_WRITE_BANDWIDTH;
+      default:
+        return 0xFF;
+    }
+  } else {
+    switch (DataType) {
+      case EFI_ACPI_HMAT_ACCESS_BANDWIDTH:
+        return XSOCKET_DDR_ACCESS_BANDWIDTH;
+      case EFI_ACPI_HMAT_READ_BANDWIDTH:
+        return XSOCKET_DDR_READ_BANDWIDTH;
+      case EFI_ACPI_HMAT_WRITE_BANDWIDTH:
+        return XSOCKET_DDR_WRITE_BANDWIDTH;
+      default:
+        return 0xFF;
+    }
+  }
+}
+
+/**
+  Get the Read/Write/Access Latency value of the memory type.
+
+  @param [in]       DataType         Type of latency value that is required (Read/Write/Access)
+  @param [in]       Type             Type of memory for which Latency is required. (DDR/DDRT)
+
+  @retval Value of the Latency associated with memory type.
+  @retval 0xFF   Input parameters are invalid.
+**/
+UINT16
+GetMemoryLatency (
+  IN     UINT8                                 DataType,
+  IN     MemoryType                            Type,
+  IN     UINT8                                 volMemMode
+ )
+{
+  if (Type == DDRT) {  // MemoryType == DDRT
+    switch (DataType) {
+      case EFI_ACPI_HMAT_ACCESS_LATENCY :
+        return DDRT_ACCESS_LATENCY;
+
+      case EFI_ACPI_HMAT_READ_LATENCY :
+        if (volMemMode == VOL_MEM_MODE_1LM) {
+          return DDRT_1LM_READ_LATENCY;
+        } else {
+          return DDRT_2LM_READ_LATENCY;
+        }
+
+      case EFI_ACPI_HMAT_WRITE_LATENCY :
+        if (volMemMode == VOL_MEM_MODE_1LM) {
+          return DDRT_1LM_WRITE_LATENCY;
+        } else {
+          return DDRT_2LM_WRITE_LATENCY;
+        }
+
+      default:
+        return 0xFF;
+    }
+  } else if (Type == DDR2LMCACHE){
+    switch (DataType) {
+      case EFI_ACPI_HMAT_ACCESS_LATENCY :
+        return DDR2LMCACHE_ACCESS_LATENCY;
+
+      case EFI_ACPI_HMAT_READ_LATENCY :
+        return DDR2LMCACHE_READ_LATENCY;
+
+      case EFI_ACPI_HMAT_WRITE_LATENCY :
+        return DDR2LMCACHE_WRITE_LATENCY;
+
+      default:
+        return 0xFF;
+    }
+  } else {
+    switch (DataType) {
+      case EFI_ACPI_HMAT_ACCESS_LATENCY :
+        return DDR_ACCESS_LATENCY;
+
+      case EFI_ACPI_HMAT_READ_LATENCY :
+        return DDR_READ_LATENCY;
+
+      case EFI_ACPI_HMAT_WRITE_LATENCY :
+        return DDR_WRITE_LATENCY;
+
+      default:
+        return 0xFF;
+    }
+  }
+}
+
+/**
+  Get the Read/Write/Access Latency value of the memory type between sockets.
+
+  @param [in]       DataType         Type of latency value that is required (Read/Write/Access)
+  @param [in]       Type             Type of memory for which Latency is required. (DDR/DDRT)
+
+  @retval Value of the Latency associated with memory type.
+  @retval 0xFF   Input parameters are invalid.
+**/
+UINT16
+GetXSocketMemoryLatency (
+  IN     UINT8                                 DataType,
+  IN     MemoryType                            Type,
+  IN     UINT8                                 volMemMode
+  )
+{
+  if (Type == DDRT) {  // MemoryType == DDRT
+    switch (DataType) {
+
+      case EFI_ACPI_HMAT_ACCESS_LATENCY :
+        return DDRT_ACCESS_LATENCY;
+
+      case EFI_ACPI_HMAT_READ_LATENCY :
+        if (volMemMode == VOL_MEM_MODE_1LM) {
+          return XSOCKET_DDRT_1LM_READ_LATENCY;
+        } else {
+          return XSOCKET_DDRT_2LM_READ_LATENCY;
+        }
+
+      case EFI_ACPI_HMAT_WRITE_LATENCY :
+        if (volMemMode == VOL_MEM_MODE_1LM) {
+          return XSOCKET_DDRT_1LM_WRITE_LATENCY;
+        } else {
+          return XSOCKET_DDRT_2LM_WRITE_LATENCY;
+        }
+
+      default:
+        return 0xFF;
+    }
+  } else if (Type == DDR2LMCACHE){
+    switch (DataType) {
+
+      case EFI_ACPI_HMAT_ACCESS_LATENCY :
+        return DDR2LMCACHE_ACCESS_LATENCY;
+
+      case EFI_ACPI_HMAT_READ_LATENCY :
+        return DDR2LMCACHE_READ_LATENCY;
+
+      case EFI_ACPI_HMAT_WRITE_LATENCY :
+        return DDR2LMCACHE_WRITE_LATENCY;
+
+      default:
+        return 0xFF;
+    }
+  } else {
+    switch (DataType) {
+
+      case EFI_ACPI_HMAT_ACCESS_LATENCY :
+        return XSOCKET_DDR_ACCESS_LATENCY;
+
+      case EFI_ACPI_HMAT_READ_LATENCY :
+        return XSOCKET_DDR_READ_LATENCY;
+
+      case EFI_ACPI_HMAT_WRITE_LATENCY :
+        return XSOCKET_DDR_WRITE_LATENCY;
+
+      default:
+        return 0xFF;
+    }
+  }
+}
+
+/**
+  Patch HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE structure.
+
+  @param [in]       Lbis             Points to HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE to be modified
+  @param [in, out]  LibsSlackSize    Points to cummulative LIBS slack size
+  @param [in]       HmatData         HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE to be consumed
+
+  @retval None
+**/
+VOID
+PatchBandWidthLbis (
+  IN     LATENCY_BANDWIDTH_INFO_STRUCTURE      **LbisPtr,
+  IN OUT UINTN                                 *LibsSlackSize,
+  IN     HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE  *HmatData,
+  IN     UINT8                                 DataType,
+  IN     MemoryType                            Type,
+  IN     UINT8                                 volMemMode
+  )
+{
+  UINT32  Row = 0;
+  UINT32  Col = 0;
+  UINT32  RowSocketId = 0;
+  UINT32  ColSocketId = 0;
+  UINT32  RowBaseIndex = 0;
+  UINT32  StructSize = 0;
+  UINT32  InitiatorIndex = 0;
+  UINT32  TargetIndex = 0;
+  LATENCY_BANDWIDTH_INFO_STRUCTURE *Lbis  = *LbisPtr;
+  UINT32  *InitiatorProximityDomainList   = (UINT32*)Lbis;
+  UINT32  *TargetProximityDomainList      = (UINT32*)Lbis;
+  UINT16  *RelativeDistanceEntry          = (UINT16*)Lbis;
+
+  Lbis->Type = SYSTEM_LOCALITY_LATENCY_BANDWIDTH_INFORMATION_STRUCTURE_TYPE;
+  Lbis->DataType = DataType;
+  Lbis->InitiatorProximityDomainsNumber = HmatData->ProcessorDomainNumber;
+  Lbis->TargetProximityDomainsNumber = HmatData->MemoryDomainNumber;
+
+  switch (Type) {
+
+    case DDR2LMCACHE:
+     Lbis->EntryBaseUnit = DDR2LMCACHE_BANDWIDTH_BASE_UNIT;
+     Lbis->Flags = EFI_ACPI_HMAT_MEMORY_HIERACHY_LAST_LEVEL_MEMORY;
+     break;
+
+    default:
+    Lbis->EntryBaseUnit = MEMORY_BANDWIDTH_BASE_UNIT;
+    Lbis->Flags = EFI_ACPI_HMAT_MEMORY_HIERACHY_MEMORY;
+  }
+
+  InitiatorProximityDomainList = (UINT32*)&(Lbis->InitiatorProximityDomainList[0]);
+  StructSize = (UINT32)((UINT8*)InitiatorProximityDomainList - (UINT8*)Lbis);
+  StructSize += (Lbis->InitiatorProximityDomainsNumber * (sizeof (UINT32)));
+  TargetProximityDomainList = (UINT32*)((UINT8*)TargetProximityDomainList + StructSize);
+  StructSize += (Lbis->TargetProximityDomainsNumber * (sizeof (UINT32)));
+  RelativeDistanceEntry = (UINT16*)((UINT8*)RelativeDistanceEntry + StructSize);
+  StructSize += (Lbis->InitiatorProximityDomainsNumber * Lbis->TargetProximityDomainsNumber * (sizeof (UINT16)));
+
+  Lbis->Length = StructSize;
+
+  for (Row = 0; Row < Lbis->InitiatorProximityDomainsNumber; Row++) {
+    *(InitiatorProximityDomainList + Row)  = Row;
+  }
+  for (Row = 0; Row < Lbis->TargetProximityDomainsNumber; Row++) {
+    *(TargetProximityDomainList + Row) = Row;
+  }
+  Row = 0;
+  for (InitiatorIndex = 0; InitiatorIndex < EFI_ACPI_HMAT_NUMBER_OF_PROCESSOR_DOMAINS; InitiatorIndex++) {
+    if (HmatData->ProcessorDomainList[InitiatorIndex] == 1) {
+      RowSocketId = HmatData->ProcessorDomainSocketIdList[InitiatorIndex];
+      RowBaseIndex = Row * Lbis->TargetProximityDomainsNumber;
+      Col = 0;
+      for (TargetIndex = 0; TargetIndex < EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS; TargetIndex++) {
+        if (HmatData->MemoryDomainList[TargetIndex].Valid == 1) {
+          ColSocketId = HmatData->MemoryDomainList[TargetIndex].PhysicalSocketId;
+          if (Type == DDR2LMCACHE) {
+            //
+            // DDR acting as cache for DDRT
+            //SocketsLinked
+            //
+            if (SocketsLinked (RowSocketId, ColSocketId)) {
+              RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryBandWidth (DataType, Type, volMemMode);
+            } else {
+              RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryBandWidth (DataType, Type, volMemMode);
+            }
+          } else if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_2LM) {
+            //
+            // Add only details for DDRT as entire DDR is acting as Cache
+            //
+            if (SocketsLinked (RowSocketId, ColSocketId)) {
+              RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryBandWidth (DataType, DDRT, volMemMode);
+            } else {
+              RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryBandWidth (DataType, DDRT, volMemMode);
+            }
+          } else {
+            //
+            // Neither cache nor 2LM, we need to add details for both DDR and DDRT
+            //
+            if ((Col / (HmatData->MemoryDomainNumber- SkippedEntries)) == 0) {
+              //
+              // DDR entries
+              //
+              if (SocketsLinked (RowSocketId, ColSocketId)) {
+                RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryBandWidth (DataType, DDR, volMemMode);
+              } else {
+                RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryBandWidth (DataType, DDR, volMemMode);
+              }
+            } else  {
+              //
+              // DDRT entries
+              //
+              if (SocketsLinked (RowSocketId, ColSocketId)) {
+                RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryBandWidth (DataType, DDRT, volMemMode);
+              } else {
+                RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryBandWidth (DataType, DDRT, volMemMode);
+              }
+            }
+          }
+          Col++;
+        } //if (HmatData->MemoryDomainList[TargetIndex].Valid == 1)
+      } // for (TargetIndex)
+      Row++;
+    } // if (HmatData->ProcessorDomainList[InitiatorIndex] == 1)
+  } //for (InitiatorIndex)
+
+  *LibsSlackSize += StructSize;
+  *LbisPtr = (LATENCY_BANDWIDTH_INFO_STRUCTURE *)((UINT8*)Lbis + StructSize);
+}
+
+/**
+  Patch HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE structure.
+
+  @param [in]       Lbis        Points to HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE to be modified
+  @param [in, out]  LibsSlackSize   Points to cumulative LIBS slack size
+  @param [in]       HmatData    HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE to be consumed
+
+  @retval None
+**/
+VOID
+PatchMemoryLatencyLbis (
+  IN     LATENCY_BANDWIDTH_INFO_STRUCTURE      **LbisPtr,
+  IN OUT UINTN                                 *LibsSlackSize,
+  IN     HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE  *HmatData,
+  IN     UINT8                                 DataType,
+  IN     MemoryType                            Type,
+  IN     UINT8                                 volMemMode
+  )
+{
+  UINT32  Row = 0;
+  UINT32  Col = 0;
+  UINT32  RowSocketId = 0;
+  UINT32  ColSocketId = 0;
+  UINT32  RowBaseIndex = 0;
+  UINT32  StructSize = 0;
+  UINT32  InitiatorIndex = 0;
+  UINT32  TargetIndex = 0;
+  LATENCY_BANDWIDTH_INFO_STRUCTURE *Lbis  = *LbisPtr;
+  UINT32  *InitiatorProximityDomainList   = (UINT32*)Lbis;
+  UINT32  *TargetProximityDomainList      = (UINT32*)Lbis;
+  UINT16  *RelativeDistanceEntry          = (UINT16*)Lbis;
+
+  Lbis->Type = SYSTEM_LOCALITY_LATENCY_BANDWIDTH_INFORMATION_STRUCTURE_TYPE;
+  Lbis->DataType = DataType;
+  Lbis->InitiatorProximityDomainsNumber = HmatData->ProcessorDomainNumber;
+  Lbis->TargetProximityDomainsNumber = HmatData->MemoryDomainNumber;
+
+  switch (Type) {
+
+    case DDR2LMCACHE:
+      Lbis->EntryBaseUnit = DDR2LMCACHE_BANDWIDTH_BASE_UNIT;
+      Lbis->Flags = EFI_ACPI_HMAT_MEMORY_HIERACHY_LAST_LEVEL_MEMORY;
+      break;
+
+    default:
+      Lbis->EntryBaseUnit = MEMORY_LATENCY_BASE_UNIT;
+      Lbis->Flags = EFI_ACPI_HMAT_MEMORY_HIERACHY_MEMORY;
+  }
+
+  InitiatorProximityDomainList = (UINT32*)&(Lbis->InitiatorProximityDomainList[0]);
+  StructSize = (UINT32)((UINT8*)InitiatorProximityDomainList - (UINT8*)Lbis);
+  StructSize += (Lbis->InitiatorProximityDomainsNumber * (sizeof (UINT32)));
+  TargetProximityDomainList = (UINT32*)((UINT8*)TargetProximityDomainList + StructSize);
+  StructSize += (Lbis->TargetProximityDomainsNumber * (sizeof (UINT32)));
+  RelativeDistanceEntry = (UINT16*)((UINT8*)RelativeDistanceEntry + StructSize);
+  StructSize += (Lbis->InitiatorProximityDomainsNumber * Lbis->TargetProximityDomainsNumber * (sizeof (UINT16)));
+
+  Lbis->Length = StructSize;
+
+  for (Row = 0; Row < Lbis->InitiatorProximityDomainsNumber; Row++) {
+    *(InitiatorProximityDomainList + Row)  = Row;
+  }
+  for (Row = 0; Row < Lbis->TargetProximityDomainsNumber; Row++) {
+    *(TargetProximityDomainList + Row) = Row;
+  }
+  Row = 0;
+  for (InitiatorIndex = 0; InitiatorIndex < EFI_ACPI_HMAT_NUMBER_OF_PROCESSOR_DOMAINS; InitiatorIndex++) {
+    if (HmatData->ProcessorDomainList[InitiatorIndex] == 1) {
+      RowSocketId = HmatData->ProcessorDomainSocketIdList[InitiatorIndex];
+      RowBaseIndex = Row * Lbis->TargetProximityDomainsNumber;
+      Col = 0;
+      for (TargetIndex = 0; TargetIndex < EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS; TargetIndex++) {
+        if (HmatData->MemoryDomainList[TargetIndex].Valid == 1) {
+          ColSocketId = HmatData->MemoryDomainList[TargetIndex].PhysicalSocketId;
+          if (Type == DDR2LMCACHE) {
+            //
+            // DDR acting as cache for DDRT
+            //
+            if (SocketsLinked (RowSocketId, ColSocketId)) {
+              RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryLatency (DataType, Type, volMemMode);
+            } else {
+              RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryLatency (DataType, Type, volMemMode);
+            }
+          } else if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_2LM) {
+            //
+            // Add only details for DDRT as entire DDR is acting as Cache
+            //
+            if (SocketsLinked (RowSocketId, ColSocketId)) {
+              RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryLatency (DataType, DDRT, volMemMode);
+            } else {
+              RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryLatency (DataType, DDRT, volMemMode);
+            }
+          } else {
+            //
+            // Neither cache nor 2LM, we need to add details for both DDR and DDRT
+            //
+            if ((Col / (HmatData->MemoryDomainNumber - SkippedEntries)) == 0) {
+              //
+              // DDR entries
+              //
+              if (SocketsLinked (RowSocketId, ColSocketId)) {
+                RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryLatency (DataType, DDR, volMemMode);
+              } else {
+                RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryLatency (DataType, DDR, volMemMode);
+              }
+            } else  {
+              //
+              // DDRT entries
+              //
+              if (SocketsLinked (RowSocketId, ColSocketId)) {
+                RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryLatency (DataType, DDRT, volMemMode);
+              } else {
+                RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryLatency (DataType, DDRT, volMemMode);
+              }
+            }
+          }
+          Col++;
+        } //if (HmatData->MemoryDomainList[TargetIndex].Valid == 1)
+      } // for (TargetIndex)
+      Row++;
+    } // if (HmatData->ProcessorDomainList[InitiatorIndex] == 1)
+  } //for (InitiatorIndex)
+
+  *LibsSlackSize += StructSize;
+  *LbisPtr = (LATENCY_BANDWIDTH_INFO_STRUCTURE *)((UINT8*)Lbis + StructSize);
+}
+
+/**
+  Patch HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE structure.
+
+  @param [in]       Lbis        Points to HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE to be modified
+  @param [in, out]  SlackSize   Points to cummulative slack size
+  @param [in]       HmatData    HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE to be consumed
+
+  @retval None
+**/
+VOID
+PatchHmatLbis (
+  IN     LATENCY_BANDWIDTH_INFO_STRUCTURE      *Lbis,
+  IN OUT UINTN                                 *SlackSize,
+  IN     HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE  *HmatData
+  )
+{
+  UINTN    LibsStructSize=0;
+  UINT8    volMemMode;
+  LATENCY_BANDWIDTH_INFO_STRUCTURE *OrginalLbis = Lbis;
+
+  volMemMode = mSystemMemoryMap->volMemMode;
+
+  DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) Populating System Locality Latency and Bandwidth Information Structure\n"));
+
+  PatchMemoryLatencyLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_READ_LATENCY, DDR, volMemMode);
+  PatchMemoryLatencyLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_WRITE_LATENCY, DDR, volMemMode);
+  PatchBandWidthLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_READ_BANDWIDTH, DDR, volMemMode);
+  PatchBandWidthLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_WRITE_BANDWIDTH, DDR, volMemMode);
+
+  if (mSystemMemoryMap->volMemMode != VOL_MEM_MODE_1LM) {
+    PatchMemoryLatencyLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_READ_LATENCY, DDR2LMCACHE, volMemMode);
+    PatchMemoryLatencyLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_WRITE_LATENCY, DDR2LMCACHE, volMemMode);
+    PatchBandWidthLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_READ_BANDWIDTH, DDR2LMCACHE, volMemMode);
+    PatchBandWidthLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_WRITE_BANDWIDTH, DDR2LMCACHE, volMemMode);
+  }
+
+  RemoveSlack (SlackSize, OrginalLbis, LibsStructSize);
+  *SlackSize += EFI_ACPI_HMAT_LBIS_COUNT * sizeof(Lbis[0]) - LibsStructSize;
+}
+
+/**
+  Get Type 17 Handles for HBM devices used as cache.
+
+  @param [in, out]  SmbiosHandles    Points to SmbiosHandles array to be modified
+  @param [in]       NumaNode         Value for NUMA Node whose memory is being cached for the specific HBM devices
+  @retval None
+**/
+VOID
+GetHbmCacheHandles (
+  IN     UINT16   *SmbiosHandles,
+  IN     UINT8    NumaNode
+  )
+{
+  EFI_STATUS                              Status = EFI_SUCCESS;
+  SMBIOS_TABLE_TYPE17                     *SmbiosType17Record;
+  EFI_SMBIOS_HANDLE                       SmbiosHandle = 0;
+  EFI_SMBIOS_PROTOCOL                     *mSmbios;
+  EFI_SMBIOS_TYPE                         SmbiosType = EFI_SMBIOS_TYPE_MEMORY_DEVICE;
+  EFI_SMBIOS_TABLE_HEADER                 *SmbiosRecord;
+  UINT8                                   HbmHandleCount = 0;
+
+  Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **) &mSmbios);
+  if (!(EFI_ERROR (Status))) {
+    while ((!(EFI_ERROR (Status))) && (SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED) ){
+      Status = mSmbios->GetNext (mSmbios, &SmbiosHandle, &SmbiosType, &SmbiosRecord, NULL);
+      SmbiosType17Record = (SMBIOS_TABLE_TYPE17 *) SmbiosRecord;
+      if ((SmbiosType17Record->TypeDetail.CacheDram == 1)  && (SmbiosType17Record->DeviceSet == NumaNode) ) {
+        SmbiosHandles[HbmHandleCount] = SmbiosType17Record->Hdr.Handle;
+        HbmHandleCount++;
+      }
+    }
+  }
+}
+
+/**
+  Patch HMAT MEMORY_SIDE_CACHE_INFORMATION_STRUCTURE substructure.
+
+  @param [in, out]  Mscis        Points to HMAT MEMORY_SIDE_CACHE_INFORMATION_STRUCTURE to be modified
+  @param [in, out]  SlackSize    Points to cumulative slack size
+  @param [in]       HmatData     HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE to be consumed
+
+  @retval None
+**/
+VOID
+PatchHmatMscis (
+  IN OUT MEMORY_SIDE_CACHE_INFORMATION_STRUCTURE  *Mscis,
+  IN OUT UINTN                                    *SlackSize,
+  IN      HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE    *HmatData
+  )
+{
+  UINT32  Index;
+  UINT32  Count = 0;
+  UINT32  UnusedCount;
+  UINT8   SmbiosHandleIndex;
+
+  DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) Populating Memory Side Cache Information Structure\n"));
+
+  for (Index = 0; Index < EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS; Index++) {
+    if ((HmatData->MemoryDomainList[Index].Valid == 0) || (HmatData->MemoryDomainList[Index].Cacheable == 0)) {
+      continue;
+    }
+
+    //
+    // Fill in fields for Cached Memory Domains
+    //
+    Mscis[Count].MemoryProximityDomain = Index;
+    Mscis[Count].CacheAttributes.Bits.TotalCacheLevels = EFI_ACPI_HMAT_ONE_LEVEL_CACHE;
+    Mscis[Count].CacheAttributes.Bits.CacheLevel = EFI_ACPI_HMAT_ONE_LEVEL_CACHE;
+    Mscis[Count].CacheAttributes.Bits.CacheLineSize = DDR4_CACHE_LINE_SIZE;
+    Mscis[Count].CacheAttributes.Bits.CacheAssociativity = EFI_ACPI_HMAT_CACHE_ASSOCIATIVITY_DIRECT_MAPPED;
+    Mscis[Count].CacheAttributes.Bits.WritePolicy = EFI_ACPI_HMAT_WRITE_POLICY_WB;
+    Mscis[Count].MemorySideCacheSize = LShiftU64 (HmatData->MemoryDomainList[Index].MemorySideCacheSize, MEM_ADDR_SHFT_VAL);
+    Mscis[Count].NumSmbiosHandles = HmatData->MemoryDomainList[Index].NumSmbiosHandles;
+    for(SmbiosHandleIndex = 0 ; SmbiosHandleIndex < HmatData->MemoryDomainList[Index].NumSmbiosHandles; SmbiosHandleIndex++){
+      Mscis[Count].SmbiosHandles[SmbiosHandleIndex] = HmatData->MemoryDomainList[Index].SmbiosHandles[SmbiosHandleIndex];
+    }
+
+    DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) MSCIS[%x] MemorySideCacheSize = 0x%lx, ProximityDomain = %x\n", Count, Mscis[Count].MemorySideCacheSize, Index));
+
+    Count++;
+  }
+
+  //
+  // Move MSCIS entries up to replace removed MSARS entries
+  //
+  if (*SlackSize && Count) {
+    RemoveSlack (SlackSize, Mscis, Count * sizeof(Mscis[0]));
+  }
+
+  //
+  // Update SlackSize for unused MSCIS entries
+  //
+  UnusedCount = EFI_ACPI_HMAT_MSCIS_COUNT - Count;
+  *SlackSize += UnusedCount * sizeof(Mscis[0]);
+}
+
+/**
+  Update the HMAT table.
+
+  @param [in, out]      HmatAcpiTable       The table to be set.
+
+  @retval EFI SUCCESS   Procedure returned successfully.
+**/
+EFI_STATUS
+PatchHmatAcpiTable (
+  IN OUT  EFI_ACPI_COMMON_HEADER  *Table
+  )
+{
+  UINTN                                         SlackSize = 0;
+  HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE          *HmatData = NULL;
+  EFI_ACPI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE *HmatAcpiTable;
+
+  if (mSystemMemoryMap == NULL) {
+
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  HmatAcpiTable = (EFI_ACPI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE *)Table;
+
+  HmatData = (HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE *) InitializeHmatData ();
+  if (HmatData == NULL) {
+    DEBUG ((DEBUG_ERROR, "ACPI (HMAT) HMAT Data could not be initialized... skipping HMAT Patch\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Patch the MSARS, SLLBIS, and MSCIS Structure from HMAT Table.
+  //
+  PatchHmatMsars (HmatAcpiTable, &SlackSize, HmatData);
+  PatchHmatLbis (HmatAcpiTable->Lbis, &SlackSize, HmatData);
+  PatchHmatMscis (HmatAcpiTable->MemSideCache, &SlackSize, HmatData);
+
+  if (HmatData != NULL) {
+    FreePool (HmatData);
+  }
+
+  //
+  // Update HMAT table size
+  //
+  HmatAcpiTable->HmatHeader.Header.Length -= (UINT32)SlackSize;
+
+  //
+  // Dump HMAT
+  //
+  DumpHmat (HmatAcpiTable);
+
+  return EFI_SUCCESS;
+}

+ 441 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibLocal.h

@@ -0,0 +1,441 @@
+/** @file
+
+  @copyright
+  Copyright 1999 - 2020 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _ACPI_PLATFORM__LIB_LOCAL_H_
+#define _ACPI_PLATFORM__LIB_LOCAL_H_
+
+//
+// Statements that include other header files
+//
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/AcpiPlatformLib.h>
+#include <Library/CpuConfigLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/SetupLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BuildAcpiTablesLib.h>
+
+#include <Guid/PlatformInfo.h>
+#include <Guid/MemoryMapData.h>
+#include <Guid/GlobalVariable.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Protocol/Smbios.h>
+#include <Protocol/SuperIo.h>
+#include <Protocol/NfitTableUpdateProtocol.h>
+#include <DataTypes.h>
+#include <IndustryStandard/SerialPortConsoleRedirectionTable.h>
+#include <IndustryStandard/HighPrecisionEventTimerTable.h>
+#include <IioRegs.h>
+#include <Platform.h>
+#include <Protocol/GlobalNvsArea.h>
+#include <Protocol/IioUds.h>
+#include <SystemBoard.h>
+#include <Protocol/SerialIo.h>
+#include <Protocol/DevicePath.h>
+#include <Register/ArchitecturalMsr.h>
+#include <PpmPolicyPeiDxeCommon.h>
+#include <Acpi/Bdat.h>
+#include <Acpi/Hpet.h>
+#include <Acpi/Mcfg.h>
+#include <Acpi/Msct.h>
+#include <Acpi/Slit.h>
+#include <Acpi/Srat.h>
+#include <Acpi/Migt.h>
+#include <Acpi/Nfit.h>
+#include <Acpi/Pcat.h>
+#include <Acpi/Pmtt.h>
+#include <Acpi/Hmat.h>
+#include <Acpi/Wsmt.h>
+#include <Acpi/amlresrc.h> // came from https://acpica.org/downloads/source_code.php acpica-win-20130214.zip/source/include
+#include <IndustryStandard/AcpiAml.h>
+
+#include <Guid/SocketMpLinkVariable.h>
+#include <Guid/SocketIioVariable.h>
+#include <Guid/SocketPowermanagementVariable.h>
+#include <Guid/SocketCommonRcVariable.h>
+
+#include <Guid/FpgaSocketVariable.h>
+#include <Fpga.h>
+#include <Register/Cpuid.h>
+#include <Protocol/DynamicSiLibraryProtocol.h>
+#include <Protocol/DynamicSiLibraryProtocol2.h>
+#include <Upi/KtiHost.h>
+
+#define OEM1_SSDT_TABLE_SIGNATURE  SIGNATURE_32('O', 'E', 'M', '1')
+#define OEM2_SSDT_TABLE_SIGNATURE  SIGNATURE_32('O', 'E', 'M', '2')
+#define OEM3_SSDT_TABLE_SIGNATURE  SIGNATURE_32('O', 'E', 'M', '3')
+#define OEM4_SSDT_TABLE_SIGNATURE  SIGNATURE_32('O', 'E', 'M', '4')
+
+#define AML_NAME_OP           0x08
+#define AML_NAME_PREFIX_SIZE  0x06
+#define AML_NAME_DWORD_SIZE   0x0C
+
+#ifndef AML_EXTERNAL_OP
+#define AML_EXTERNAL_OP       0x15 /* ACPI 6.0 */
+#endif
+
+#define GPSS_FVID_MAX_STATES  40  // Greater Than 16 p-state support
+
+//
+// mCpuPCPSInfo usage
+//
+#define B_PCPS_DISABLE                     (1 << 17) // Bit 17
+#define B_PCPS_HT_ENABLE                   (1 << 16) // Bit 16
+#define PCIE_BUS_0         0x00
+#define PCIE_BUS_1         0x01
+#define PCIE_BUS_2         0x02
+#define PCIE_BUS_3         0x03
+#define PCIE_BUS_4         0x04
+#define PCIE_BUS_5         0x05
+
+#define PCIE_PORT_ALL_FUNC 0x00
+
+#define PCIE_PORT_0_DEV    0x00
+
+#define PCIE_PORT_1A_DEV   0x00
+#define PCIE_PORT_1B_DEV   0x01
+#define PCIE_PORT_1C_DEV   0x02
+#define PCIE_PORT_1D_DEV   0x03
+
+#define PCIE_PORT_2A_DEV   0x00
+#define PCIE_PORT_2B_DEV   0x01
+#define PCIE_PORT_2C_DEV   0x02
+#define PCIE_PORT_2D_DEV   0x03
+
+#define PCIE_PORT_3A_DEV   0x00
+#define PCIE_PORT_3B_DEV   0x01
+#define PCIE_PORT_3C_DEV   0x02
+#define PCIE_PORT_3D_DEV   0x03
+
+#define PCIE_PORT_4A_DEV   0x00
+#define PCIE_PORT_4B_DEV   0x01
+#define PCIE_PORT_4C_DEV   0x02
+#define PCIE_PORT_4D_DEV   0x03
+
+#define PCIE_PORT_5_DEV   0x00
+
+#define MAX_IO_APICS_10NM   1
+
+//
+// Define flag bits
+//
+#define POLARITY_ACTIVE_HIGH   0x01
+#define POLARITY_ACTIVE_LOW    0x03
+#define TRIGGERMODE_EDGE       0x04
+#define TRIGGERMODE_LEVEL      0x0C
+
+#pragma pack(1)
+typedef struct {
+  UINT32   AcpiProcessorId;
+  UINT32   ApicId;
+  UINT32   Flags;
+  UINT32   SocketNum;
+} CPU_ID_ORDER_MAP;
+
+typedef struct {
+  UINT8   AcpiProcessorId;
+  UINT8   ApicId;
+  UINT16  Flags;
+} CPU_ID_MAP;
+
+typedef struct {
+  UINT8   StartByte;
+  UINT32  NameStr;
+  UINT8   Size;
+  UINT32  Value;
+} ACPI_NAMEPACK_DWORD;
+
+typedef struct {
+  UINT8   StartByte;
+  UINT32  NameStr;
+  UINT8   OpCode;
+  UINT16  Size;                     // Hardcode to 16bit width because the table we use is fixed size
+  UINT8   NumEntries;
+} ACPI_NAME_COMMAND;
+
+typedef struct {
+  UINT8   PackageOp;
+  UINT8   PkgLeadByte;
+  UINT8   NumEntries;
+  UINT8   DwordPrefix0;
+  UINT32  CoreFreq;
+  UINT8   DwordPrefix1;
+  UINT32  Power;
+  UINT8   DwordPrefix2;
+  UINT32  TransLatency;
+  UINT8   DwordPrefix3;
+  UINT32  BMLatency;
+  UINT8   DwordPrefix4;
+  UINT32  Control;
+  UINT8   DwordPrefix5;
+  UINT32  Status;
+} PSS_PACKAGE;
+
+typedef struct {
+  UINT8     NameOp;           // 08h ;First opcode is a NameOp.
+  UINT32    PackageName;      // PSDC/PSDE
+  UINT8     Length;
+  UINT8     DwordPrefix1;
+  UINT8     Revision;
+  UINT8     PackageOp;
+  UINT8     PackageLen;
+  UINT8     PackLen;
+  UINT16    WordValue1;
+  UINT16    WordValue2;
+  UINT8     BytePrefix2;
+  UINT32    Domain;
+  UINT8     BytePrefix3;
+  UINT8     CoordType;        // 0xFC(SW_ALL), 0xFE(HW_ALL)
+  UINT8     BytePrefix4;
+  UINT32    NumProcessors;
+} PSD_PACKAGE_LAYOUT;
+
+struct CpcRegPack {
+  UINT8    ResourceOp;           // 11h
+  UINT8    Length;               // 14h
+  UINT32   FFixedHW;
+  UINT32   RegisterBitsUsage;
+  UINT32   RegisterBitsShift;
+  UINT32   RegisterOffset;
+  UINT32   RegisterByteSize;
+};
+
+typedef struct {
+  UINT8  ExternalOp;
+  UINT8  RootChar;
+  UINT8  MultiNamePrefix;
+  UINT8  SegCount;
+  UINT32 NameStr[0];
+} EXTERNAL_OBJECT_DECL;
+
+#define ACPI_NAME_COMMAND_FROM_NAME_STR(a)  BASE_CR (a, ACPI_NAME_COMMAND, NameStr)
+#define ACPI_NAME_COMMAND_FROM_NAMEPACK_STR(a)  BASE_CR (a, ACPI_NAMEPACK_DWORD, NameStr)
+#define ACPI_EXTERNAL_OBJECT_DECL_FROM_NAME_STR(a) BASE_CR (a, EXTERNAL_OBJECT_DECL, NameStr)
+
+//
+// Private Driver Data
+//
+//
+// Define Union of IO APIC & Local APIC structure;
+//
+typedef union {
+  EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_STRUCTURE AcpiLocalApic;
+  EFI_ACPI_6_2_IO_APIC_STRUCTURE              AcpiIoApic;
+  EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_STRUCTURE AcpiLocalx2Apic;
+  struct {
+    UINT8 Type;
+    UINT8 Length;
+  } AcpiApicCommon;
+} ACPI_APIC_STRUCTURE_PTR;
+
+#pragma pack()
+
+EFI_STATUS
+PatchBdatAcpiTable (
+  IN OUT  EFI_ACPI_COMMON_HEADER  *Table
+  );
+
+/**
+  Build from scratch and install the MADT.
+
+  @retval EFI_SUCCESS           The MADT was installed successfully.
+  @retval EFI_OUT_OF_RESOURCES  Could not allocate required structures.
+**/
+EFI_STATUS
+InstallMadtFromScratch (
+  VOID
+  );
+
+EFI_STATUS
+InstallSratTable (
+  VOID
+  );
+
+EFI_STATUS
+PatchFadtTable(
+   IN OUT   EFI_ACPI_COMMON_HEADER  *Table
+   );
+
+EFI_STATUS
+PatchDsdtTable (
+  IN OUT   EFI_ACPI_COMMON_HEADER   *Table
+  );
+
+EFI_STATUS
+PatchMcfgAcpiTable (
+  IN OUT  EFI_ACPI_COMMON_HEADER  *Table
+  );
+
+EFI_STATUS
+PatchSLitTable(
+   IN OUT   EFI_ACPI_COMMON_HEADER  *Table
+   );
+
+EFI_STATUS
+InstallSlitTable(
+   VOID
+   );
+
+/**
+  Finds the Proximity Domain which the element in the Memory Map belongs to.
+
+  @param [in]  SocketId        SocketId which the element belongs to.
+  @param [in]  MemType         MemType of the element.
+  @param [in]  SncEnabled      Bit to indicate if SNC is enabled in the setup options.
+  @param [in]  ImcInterBitmap  IMC interleave bitmap for this element.
+  @param [in]  MemMode         Current memory mode. 1LM, 2LM etc.
+  @param [in]  LastDomainId    Last Domain ID.
+
+  @retval Proximity Domain.
+
+**/
+UINT32
+ProximityDomainOf (
+  UINT8  SocketId,
+  UINT16 MemType,
+  UINT8  MaxEnabledImc,
+  UINT8  SncEnabled,
+  UINT8  SncNumOfCluster,
+  UINT8  ImcInterBitmap,
+  UINT8  MemMode,
+  UINT32 LastDomainId
+  );
+
+EFI_STATUS
+PatchSratTable (
+   IN OUT   STATIC_RESOURCE_AFFINITY_TABLE  *Table
+   );
+
+EFI_STATUS
+PatchSsdtTable (
+  IN OUT   EFI_ACPI_COMMON_HEADER   *Table,
+  IN OUT EFI_ACPI_TABLE_VERSION     *Version
+  );
+
+EFI_STATUS
+PatchCpuPmSsdtTable (
+  IN OUT   EFI_ACPI_COMMON_HEADER   *Table
+  );
+
+EFI_STATUS
+PatchOem1SsdtTable (
+  IN OUT   EFI_ACPI_COMMON_HEADER   *Table
+  );
+
+EFI_STATUS
+PatchOem2SsdtTable (
+  IN OUT   EFI_ACPI_COMMON_HEADER   *Table
+  );
+
+EFI_STATUS
+PatchOem3SsdtTable (
+  IN OUT   EFI_ACPI_COMMON_HEADER   *Table
+  );
+
+EFI_STATUS
+PatchOem4SsdtTable (
+  IN OUT   EFI_ACPI_COMMON_HEADER   *Table
+  );
+
+EFI_STATUS
+UpdateNfitTable (
+   IN OUT   EFI_ACPI_COMMON_HEADER  *Table
+   );
+
+EFI_STATUS
+UpdatePcatTable (
+   IN OUT   EFI_ACPI_COMMON_HEADER  *Table
+   );
+
+/**
+  Detect the APICID map and initialize the module global pointer.
+**/
+VOID
+DetectApicIdMap (
+  VOID
+  );
+
+/**
+  Sort CPU Local APIC Information.
+
+  This function gets the CPU local APIC information from the MP service
+  protocol into the local table structure, and sorts it based on APIC ID.
+
+  @retval EFI_SUCCESS   Local APIC information was successfully sorted.
+**/
+EFI_STATUS
+SortCpuLocalApicInTable (
+  VOID
+  );
+
+/**
+  Get the socket logical index.
+
+  This function convert the socket physical index to logical index (0 based).
+  If the specified physical socket is not enabled, an invalid logical index 0xff
+  will be returned. The socket physical index and logical index will be the same
+  if the indexes of enabled sockets are continuous.
+
+  @param[in] SocketPhysicalId    Socket physical index.
+
+  @retval Socket logical index.
+**/
+UINT8
+GetSocketLogicalId (
+  IN UINT8  SocketPhysicalId
+  );
+
+/**
+  Get the socket physical index.
+
+  This function convert the socket logical index to physical index (0 based).
+  If the specified logical socket does not exist, an invalid physical index 0xff
+  will be returned. The socket physical index and logical index will be the same
+  if the indexes of enabled sockets are continuous.
+
+  @param[in] SocketLogicalId    Socket logical index.
+
+  @retval Socket physical index.
+**/
+UINT8
+GetSocketPhysicalId (
+  IN UINT8  SocketlogicId
+  );
+
+/**
+  Verifies whether sockets are linked
+
+  @param[in]      SourceSocket  Source Socket ID
+  @param[in]      TargetSocket  Targer Socket ID
+
+  @retval TRUE link between source socket and target socket was found
+          FALSE otherwise
+
+**/
+BOOLEAN
+SocketsLinked (
+  IN UINT32  SourceSocket,
+  IN UINT32  TargetSocket
+  );
+
+//
+// AcpiPlatformTableLib private share
+//
+extern EFI_MP_SERVICES_PROTOCOL    *mMpService;
+extern BOOLEAN                     mCpuOrderSorted;
+extern CPU_ID_ORDER_MAP            mCpuApicIdOrderTable[];
+extern UINTN                       mNumberOfCPUs;
+extern UINTN                       mNumberOfEnabledCPUs;
+extern AML_OFFSET_TABLE_ENTRY      *mAmlOffsetTablePointer;
+extern CPU_CONFIG_CONTEXT_BUFFER  *mCpuConfigLibConfigContextBuffer;
+
+
+#endif

+ 134 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMcfg.c

@@ -0,0 +1,134 @@
+/** @file
+  ACPI Platform Driver Hooks
+
+  @copyright
+  Copyright 1996 - 2015 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include "AcpiPlatformLibLocal.h"
+
+
+extern BIOS_ACPI_PARAM              *mAcpiParameter;
+extern EFI_IIO_UDS_PROTOCOL         *mIioUds;
+extern CPU_CSR_ACCESS_VAR           *mCpuCsrAccessVarPtr;
+extern SYSTEM_CONFIGURATION         mSystemConfiguration;
+
+EFI_STATUS
+PatchMcfgAcpiTable (
+  IN OUT  EFI_ACPI_COMMON_HEADER  *Table
+  )
+{
+  UINT8     NodeId;
+  UINT8     NodeCount;
+  EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE *McfgTable;
+
+  McfgTable = (EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE *)Table;
+
+  //
+  // mAcpiParameter memory buffer has been zero'ed out, so mAcpiParameter->PcieSegNum[] are 0's
+  // Patch \_SB.PSYS.SGEN with User Setup Option data
+  //
+  //
+  // dynamically allow multi-seg support
+  //
+  mAcpiParameter->PcieMultiSegSupport = 0;
+  for (NodeId = 0; NodeId < MAX_SOCKET; NodeId++) {
+    if ((UINT16) (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[NodeId].PcieSegment) > 0) {
+      mAcpiParameter->PcieMultiSegSupport = 1;
+      break;
+    }
+  }
+
+  //
+  // Update MCFG table entries (segment number, base addr and start/end bus numbers)
+  //
+  if (mAcpiParameter->PcieMultiSegSupport == 0) {
+
+    //
+    // Original code for single  PCIe segment start
+    //
+    McfgTable->Segment[0].BaseAddress = mIioUds->IioUdsPtr->PlatformData.PciExpressBase;
+    McfgTable->Segment[0].EndBusNumber = (UINT8)RShiftU64 (mIioUds->IioUdsPtr->PlatformData.PciExpressSize, 20) - 1;
+    //
+    // Original code for single  PCIe segment end
+    //
+
+    //
+    // Single segment with segment number as 0
+    //
+    McfgTable->Segment[0].PciSegmentGroupNumber = 0;
+    NodeCount = 1;
+
+  } else {
+    //
+    // PCIe Multi-Segment handling - Assume each CPU socket as a segment, and copy Segement info from IioUds HOB to MCFG table entries
+    //
+
+    //
+    // Segment count = 0
+    //
+    NodeCount = 0;
+
+    for (NodeId = 0; NodeId < MAX_SOCKET; NodeId++) {
+
+      //
+      // Skip a socket if it does not exist or does not contain valid bus range data
+      //
+      if ( (UINT8)(mCpuCsrAccessVarPtr->SocketLastBus[NodeId]) ==
+            (UINT8)(mCpuCsrAccessVarPtr->SocketFirstBus[NodeId]) ) {
+        continue;
+      }
+
+      //
+      // Copy PCIe Segement info from IioUds HOB to MCFG table entries
+      //
+      McfgTable->Segment[NodeCount].PciSegmentGroupNumber = (UINT16)(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[NodeId].PcieSegment);
+
+      McfgTable->Segment[NodeCount].BaseAddress = \
+        LShiftU64 (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[NodeId].SegMmcfgBase.hi, 32) + \
+        (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[NodeId].SegMmcfgBase.lo);
+
+      McfgTable->Segment[NodeCount].StartBusNumber = (UINT8)(mCpuCsrAccessVarPtr->SocketFirstBus[NodeId]);
+
+      McfgTable->Segment[NodeCount].EndBusNumber = (UINT8)(mCpuCsrAccessVarPtr->SocketLastBus[NodeId]);
+
+      //
+      // Update segment number returned by AML  _SEG() .  It resides in mAcpiParameter region now.
+      //
+      mAcpiParameter->PcieSegNum[NodeId] = (UINT8)(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[NodeId].PcieSegment);
+
+      //
+      // Update count of valid segments
+      //
+      NodeCount++;
+    }
+  }
+
+  //
+  // Set MCFG table "Length" field based on the number of PCIe segments enumerated so far
+  //
+  McfgTable->Header.Header.Length = \
+    sizeof (EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER) + \
+    sizeof (EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE) * NodeCount;
+
+  //
+  // Debug dump of MCFG table
+  //
+  DEBUG ((DEBUG_ERROR, "ACPI MCFG table @ address 0x%x\n", Table ));
+  DEBUG ((DEBUG_ERROR, "  Multi-Seg Support = %x\n", mAcpiParameter->PcieMultiSegSupport));
+  DEBUG ((DEBUG_ERROR, "  Number of Segments (sockets): %2d\n", NodeCount ));
+  DEBUG ((DEBUG_ERROR, "  Table Length = 0x%x\n\n", McfgTable->Header.Header.Length ));
+  for (NodeId = 0; NodeId < NodeCount; NodeId ++) {
+    DEBUG ((DEBUG_ERROR, "   Segment[%2d].BaseAddress = %x\n",  NodeId, McfgTable->Segment[NodeId].BaseAddress));
+    DEBUG ((DEBUG_ERROR, "   Segment[%2d].PciSegmentGroupNumber = %x\n", NodeId, McfgTable->Segment[NodeId].PciSegmentGroupNumber));
+    DEBUG ((DEBUG_ERROR, "   Segment[%2d].StartBusNumber = %x\n", NodeId, McfgTable->Segment[NodeId].StartBusNumber));
+    DEBUG ((DEBUG_ERROR, "   Segment[%2d].EndBusNumber = %x\n\n", NodeId, McfgTable->Segment[NodeId].EndBusNumber));
+  }
+
+  return EFI_SUCCESS;
+}

+ 69 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMigt.c

@@ -0,0 +1,69 @@
+/** @file
+  ACPI Platform Driver Hooks
+
+  @copyright
+  Copyright 1996 - 2018 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include "AcpiPlatformLibLocal.h"
+
+extern BIOS_ACPI_PARAM      *mAcpiParameter;
+
+/**
+    Update the MIGT ACPI table
+
+    @param *TableHeader   - The table to be set
+
+    @retval EFI_SUCCESS -  Returns Success
+**/
+EFI_STATUS
+PatchMigtAcpiTable (
+  IN OUT   EFI_ACPI_COMMON_HEADER   *Table
+  )
+{
+  EFI_STATUS        Status;
+  UINT64            Address;
+  UINTN             idx;
+  UINT8             checksum;
+  EFI_MIGT_ACPI_DESCRIPTION_TABLE *MigtAcpiTable;
+
+  MigtAcpiTable = (EFI_MIGT_ACPI_DESCRIPTION_TABLE *)Table;
+  Address = 0xffffffff;
+
+  Status  = gBS->AllocatePages (
+                   AllocateMaxAddress,
+                   EfiACPIMemoryNVS,
+                   1,     //page
+                   &Address
+                   );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // update MIGT ACPI table
+  //
+  MigtAcpiTable->ActionRegion.Address = Address;
+
+  //
+  // update checksum
+  //
+  MigtAcpiTable->Header.Checksum = 0;
+  checksum = 0;
+  for(idx = 0; idx < sizeof(EFI_MIGT_ACPI_DESCRIPTION_TABLE); idx++) {
+    checksum = checksum + (UINT8) (((UINT8 *)(MigtAcpiTable))[idx]);
+  }
+  MigtAcpiTable->Header.Checksum = (UINT8) (0 - checksum);
+
+  //
+  // Update Migration Action Region GAS address
+  //
+  mAcpiParameter->MigrationActionRegionAddress = Address;
+
+  return Status;
+}

+ 101 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMsct.c

@@ -0,0 +1,101 @@
+/** @file
+  ACPI Platform Driver Hooks
+
+  @copyright
+  Copyright 1996 - 2020 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include "AcpiPlatformLibLocal.h"
+
+/**
+  Update the MSCT ACPI table
+
+  @param *MsctAcpiTable - The table to be set
+
+  @retval EFI_SUCCESS -  Returns Success
+**/
+EFI_STATUS
+PatchMsctAcpiTable (
+  IN OUT   EFI_ACPI_COMMON_HEADER   *Table
+  )
+{
+  UINTN                       idx;
+  UINT8                       checksum;
+  UINT32                      MaxPhysicalAddressBit;
+  EFI_CPUID_REGISTER          CpuidLeafInfo;
+  EFI_ACPI_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE *MsctAcpiTable = NULL;
+  UINT32                      MaxThreadCapacity;
+  UINT32                      MaxSocketCount;
+  EFI_STATUS                  Status = EFI_SUCCESS;
+  DYNAMIC_SI_LIBARY_PROTOCOL2  *DynamicSiLibraryProtocol2 = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  MsctAcpiTable = (EFI_ACPI_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE *)Table;
+
+  //
+  // If SNC is enabled set the Maximum number of Proximity domains accordingly
+  //
+  MaxSocketCount = FixedPcdGet32 (PcdMaxCpuSocketCount);
+
+  if (DynamicSiLibraryProtocol2->GetNumOfClusterPerSystem () != 0) {
+    MsctAcpiTable->MaxNumProxDom = MaxSocketCount * DynamicSiLibraryProtocol2->GetNumOfClusterPerSystem () - 1;
+  }
+
+  //
+  // Update Maximum Physical Address
+  // Get the number of address lines; Maximum Physical Address is 2^MaxPhysicalAddressBit - 1.
+  // If CPUID does not support reporting the max physical address, then use a max value of 36 as per SDM 3A, 4.1.4.
+  //
+  AsmCpuid (CPUID_EXTENDED_FUNCTION, &CpuidLeafInfo.RegEax, NULL, NULL, NULL);
+  MaxPhysicalAddressBit = 36;
+  if (CpuidLeafInfo.RegEax >= (UINT32) CPUID_VIR_PHY_ADDRESS_SIZE) {
+    AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &CpuidLeafInfo.RegEax, NULL, NULL, NULL);
+    MaxPhysicalAddressBit = (UINT8) CpuidLeafInfo.RegEax;
+  }
+
+  MsctAcpiTable->MaxPhysicalAddress = (LShiftU64 (0x01, MaxPhysicalAddressBit) - 1);
+
+  MaxPhysicalAddressBit = DynamicSiLibraryProtocol2->GetMaxPhysicalAddrBits ();
+
+  MsctAcpiTable->MaxPhysicalAddress = (LShiftU64 (0x01, MaxPhysicalAddressBit) - 1);
+
+  //
+  // First Proximity Domain Information Structure reports characteristics for all proximity domains,
+  // since the characteristics are the same for all proximity domains.
+  //
+  MsctAcpiTable->ProxDomInfoStructure[0].ProxDomRangeLow  = 0;
+  MsctAcpiTable->ProxDomInfoStructure[0].ProxDomRangeHigh = MsctAcpiTable->MaxNumProxDom;
+
+  //
+  // Max Number of Threads that the processor can have MaxThreadCapacity
+  //
+  AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 1, NULL, &MaxThreadCapacity, NULL, NULL);
+  MsctAcpiTable->ProxDomInfoStructure[0].MaxProcessorCapacity = MaxThreadCapacity;
+
+  //
+  // Max Memory capacity per proximity domain
+  //
+  MsctAcpiTable->ProxDomInfoStructure[0].MaxMemoryCapacity = MsctAcpiTable->MaxPhysicalAddress;
+
+  //
+  // Update Checksum
+  //
+  MsctAcpiTable->Header.Checksum = 0;
+  checksum = 0;
+  for(idx = 0; idx < sizeof(EFI_ACPI_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE); idx++) {
+    checksum = checksum + (UINT8) (((UINT8 *)(MsctAcpiTable))[idx]);
+  }
+  MsctAcpiTable->Header.Checksum = (UINT8) (0 - checksum);
+
+  return EFI_SUCCESS;
+}

+ 45 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibNfit.c

@@ -0,0 +1,45 @@
+/** @file
+  ACPI Platform Driver Hooks
+
+  @copyright
+  Copyright 1996 - 2019 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include "AcpiPlatformLibLocal.h"
+
+/**
+  This function locates the CrystalRidge protocol and JedecNvdimm protocol
+  and calls the update ACPI tables functions defined there to update/build
+  the NVDIMM F/W Interface Table (NFIT). It builds the NFIT table which gets
+  published in ACPI XSDT.
+
+  @param[in,out] Table      Pointer to NFIT which will be build in
+                            CR Protocol and will be publised in ACPI XSDT.
+
+  @retval EFI_SUCCESS       Table successfully updated.
+  @retval EFI_UNSUPPORTED   Table not updated.
+**/
+EFI_STATUS
+UpdateNfitTable (
+  IN OUT   EFI_ACPI_COMMON_HEADER  *Table
+  )
+{
+  EFI_NFIT_TABLE_UPDATE_PROTOCOL    *NfitTableUpdateProtocol = NULL;
+  EFI_STATUS                        Status;
+
+  Status = gBS->LocateProtocol (&gEfiNfitTableUpdateProtocolGuid, NULL, &NfitTableUpdateProtocol);
+
+  if (!EFI_ERROR (Status)) {
+    Status = NfitTableUpdateProtocol->UpdateAcpiTable ((UINT64*) Table);
+  } else {
+    DEBUG ((DEBUG_ERROR, "Cannot find NfitTableUpdateProtocol\n"));
+  }
+  DEBUG ((DEBUG_INFO, "NFIT Update Status: 0x%x\n", Status));
+
+  return Status;
+}

+ 42 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibPcat.c

@@ -0,0 +1,42 @@
+/** @file
+  ACPI Platform Driver Hooks
+
+  @copyright
+  Copyright 1996 - 2016 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include "AcpiPlatformLibLocal.h"
+
+/**
+  This function  locates the CrystalRidge Protocol and calls
+  into one of its interface function (UpdateAcpiPcatTable) to
+  update/build the PCAT (Platform Capability Attribute Table).
+  And this table gets published in ACPI XSDT.
+
+  @param *Table       - Pointer to PCAT table which will be
+          build in CR Protocol and will be publised in ACPI
+          XSDT.
+  @retval Status      - Return Status
+**/
+EFI_STATUS
+UpdatePcatTable (
+   IN OUT   EFI_ACPI_COMMON_HEADER  *Table
+   )
+{
+  EFI_STATUS                      Status;
+  DYNAMIC_SI_LIBARY_PROTOCOL2     *DynamicSiLibraryProtocol2 = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  Status = DynamicSiLibraryProtocol2->UpdatePcatTable (Table);
+  return EFI_SUCCESS;
+}

+ 267 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibPmtt.c

@@ -0,0 +1,267 @@
+/** @file
+  ACPI Platform Driver Hooks
+
+  @copyright
+  Copyright 2016 - 2020 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "AcpiPlatformLibLocal.h"
+#include <Protocol/SmbiosMemInfo.h>
+
+extern struct SystemMemoryMapHob   *mSystemMemoryMap;
+
+/******************************************************************************
+ * Definitions.
+ ******************************************************************************/
+//#define PMTTDEBUG_ENABLED 1
+#if PMTTDEBUG_ENABLED
+#define PMTTDEBUG(Expr) _DEBUG(Expr)
+#else
+#define PMTTDEBUG(Expr)
+#endif
+#ifndef NELEMENTS
+#define NELEMENTS(Array) (sizeof(Array)/sizeof((Array)[0]))
+#endif
+
+
+//
+// PMTT GUID variables
+//
+const EFI_GUID  gEfiPmttTypeDieGuid = PMTT_TYPE_DIE_GUID;
+const EFI_GUID  gEfiPmttTypeChannelGuid = PMTT_TYPE_CHANNEL_GUID;
+const EFI_GUID  gEfiPmttTypeSlotGuid = PMTT_TYPE_SLOT_GUID;
+
+/******************************************************************************
+ * Functions.
+ ******************************************************************************/
+
+EFI_STATUS
+PatchPlatformMemoryTopologyTable (
+  IN OUT EFI_ACPI_COMMON_HEADER       *Table
+  )
+{
+  UINT8                                Socket;
+  UINT8                                Die;
+  UINT8                                Imc;
+  UINT8                                Channel;
+  UINT8                                ChannelIndex;
+  UINT8                                Dimm;
+  SMBIOS_DIMM_INFO                     DimmInfo;
+  SMBIOS_MEM_INFO_PROTOCOL             *SmbiosInfoProtocol;
+  EFI_STATUS                           Status;
+  ACPI_PLATFORM_MEMORY_TOPOLOGY_TABLE  *PmttTable = (ACPI_PLATFORM_MEMORY_TOPOLOGY_TABLE*)Table;
+  UINT8                                MaxImc;
+  UINT8                                MaxChPerImc;
+  UINT8                                DieCnt;
+
+  DYNAMIC_SI_LIBARY_PROTOCOL2         *DynamicSiLibraryProtocol2 = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  MaxImc = DynamicSiLibraryProtocol2->GetMaxImc ();
+  MaxChPerImc = DynamicSiLibraryProtocol2->GetNumChannelPerMc ();
+
+  ASSERT (PmttTable->Header.Signature == ACPI_PMTT_TABLE_SIGNATURE);
+
+  Status = gBS->LocateProtocol (&gSmbiosMemInfoProtocolGuid, NULL, (VOID**)&SmbiosInfoProtocol);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "[ACPI] (PMTT) Cannot locate SmbiosMemInfoProtocol! (%r)\n", Status));
+    ASSERT_EFI_ERROR (Status);
+    SmbiosInfoProtocol = NULL;
+  }
+
+  for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+
+    PmttTable->Socket[Socket].Type      = ACPI_TOP_LEVEL_SOCKET;
+    PmttTable->Socket[Socket].SckIdent  = Socket;
+    PmttTable->Socket[Socket].Length    = sizeof(PmttTable->Socket[Socket]) - sizeof(ACPI_PMTT_DIE_DEVICE);
+    PmttTable->Socket[Socket].Flag      = 0;
+    PmttTable->Socket[Socket].NumOfMemoryDevices = 0;
+
+    if (mSystemMemoryMap->Socket[Socket].SocketEnabled) {
+      PmttTable->Socket[Socket].Flag |= (PMTT_TOP_LEVEL_AGGREGATOR_DEVICE | PMTT_PHYSICAL_ELEMENT_OF_TOPOLOGY);
+      PmttTable->NumOfMemoryDevices++;
+    } else {
+      continue;
+    }
+
+    DieCnt =   DynamicSiLibraryProtocol2->GetAcpiDieCount (Socket);
+    for (Die = 0; Die < DieCnt; Die++) {
+
+      PmttTable->Socket[Socket].Die[Die].Type = ACPI_TOP_LEVEL_VENDOR_SPECIFIC_DEVICE;
+      PmttTable->Socket[Socket].Die[Die].Length = sizeof(PmttTable->Socket[Socket].Die[Die]) - MAX_IMC * sizeof(ACPI_PMTT_IMC_DEVICE);
+      PmttTable->Socket[Socket].Die[Die].Flag = 0;
+      PmttTable->Socket[Socket].Die[Die].Flag |= PMTT_PHYSICAL_ELEMENT_OF_TOPOLOGY;
+      PmttTable->Socket[Socket].Die[Die].NumOfMemoryDevices = 0;
+      PmttTable->Socket[Socket].Die[Die].DieId = Die;
+      CopyGuid (&PmttTable->Socket[Socket].Die[Die].TypeUuid, &gEfiPmttTypeDieGuid);
+
+      PmttTable->Socket[Socket].NumOfMemoryDevices++;
+
+      for (Imc = 0; Imc < MaxImc; Imc++) {
+
+        PmttTable->Socket[Socket].Die[Die].Imc[Imc].Type = ACPI_TOP_LEVEL_IMC;
+        PmttTable->Socket[Socket].Die[Die].Imc[Imc].Length = sizeof(PmttTable->Socket[Socket].Die[Die].Imc[Imc]) - MAX_MC_CH * sizeof(ACPI_PMTT_CHANNEL_DEVICE);
+        PmttTable->Socket[Socket].Die[Die].Imc[Imc].Flag = 0;
+        PmttTable->Socket[Socket].Die[Die].Imc[Imc].NumOfMemoryDevices = 0;
+        PmttTable->Socket[Socket].Die[Die].Imc[Imc].ImcId = Imc;
+
+        if (mSystemMemoryMap->Socket[Socket].imcEnabled[Imc]) {
+          PmttTable->Socket[Socket].Die[Die].Imc[Imc].Flag |= PMTT_PHYSICAL_ELEMENT_OF_TOPOLOGY;
+          PmttTable->Socket[Socket].Die[Die].NumOfMemoryDevices++;
+        } else {
+          continue;
+        }
+
+        for (Channel = 0; Channel < MaxChPerImc; Channel++) {
+
+          ChannelIndex = MEM_IMCCH_TO_SKTCH(Imc, Channel);
+          PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Type = ACPI_TOP_LEVEL_VENDOR_SPECIFIC_DEVICE;
+          PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Length = sizeof(PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel]) - MAX_DIMM * sizeof(ACPI_PMTT_SLOT_DEVICE);
+          PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Flag = 0;
+          PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].NumOfMemoryDevices = 0;
+          PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].ChannelId = Channel;
+          CopyGuid (&(PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].TypeUuid), &gEfiPmttTypeChannelGuid);
+
+          if (mSystemMemoryMap->Socket[Socket].ChannelInfo[ChannelIndex].Enabled) {
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Flag |= PMTT_PHYSICAL_ELEMENT_OF_TOPOLOGY;
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].NumOfMemoryDevices++;
+          } else {
+            continue;
+          }
+
+          for (Dimm = 0; Dimm < MAX_DIMM; Dimm++) {
+            //
+            // Looping through the each DIMM on the IMC.
+            //
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Type = ACPI_TOP_LEVEL_VENDOR_SPECIFIC_DEVICE;
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Length = sizeof(PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm]) - sizeof(ACPI_PMTT_DIMM_DEVICE);
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Flag |= PMTT_PHYSICAL_ELEMENT_OF_TOPOLOGY;
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].NumOfMemoryDevices = 0;
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].SlotId = Dimm;
+            CopyGuid (&PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].TypeUuid, &gEfiPmttTypeSlotGuid);
+
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Type = PHYSICAL_COMPONENT_IDENTIFIER_TYPE_DIMM;
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Length = sizeof(PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm);
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.NumOfMemoryDevices = 0;
+
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Flag = 0;
+
+            if (!mSystemMemoryMap->Socket[Socket].ChannelInfo[ChannelIndex].DimmInfo[Dimm].Present) {
+              continue;
+            }
+
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Flag |= PMTT_PHYSICAL_ELEMENT_OF_TOPOLOGY;
+
+            if (mSystemMemoryMap->Socket[Socket].ChannelInfo[ChannelIndex].DimmInfo[Dimm].DcpmmPresent) {
+              PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Flag |= PMTT_AEP_DIMM;
+            }
+            //
+            // Get SMBIOS handle for the DIMM. If handle not found use FFFFFFFFh.
+            //
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.SmbiosHandle = (UINT32)-1;
+            if (SmbiosInfoProtocol != NULL) {
+
+              DimmInfo.Socket = Socket;
+              DimmInfo.Imc = Imc;
+              DimmInfo.Channel = Channel;
+              DimmInfo.Dimm = Dimm;
+              Status = SmbiosInfoProtocol->SmbiosGetDimmByLocation (SmbiosInfoProtocol, &DimmInfo);
+              if (!EFI_ERROR (Status)) {
+                PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.SmbiosHandle = DimmInfo.Type17Handle;
+              }
+            }
+
+            if (!mSystemMemoryMap->Socket[Socket].ChannelInfo[ChannelIndex].DimmInfo[Dimm].Enabled) {
+              continue;
+            }
+
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].NumOfMemoryDevices++;
+            PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].NumOfMemoryDevices++;
+          } // for (Dimm...)
+        } // for (Channel...)
+      } // for (Imc...)
+    } // for (Die...)
+  } // for (Skt...)
+  //
+  // Dump the strucutre for debug purpose
+  //
+  PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) Signature:       0x%08X\n", PmttTable->Header.Signature));
+  PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) Length:          %d\n", PmttTable->Header.Length));
+  PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) Revision:        %d\n", PmttTable->Header.Revision));
+  PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) Checksum:         %d\n", PmttTable->Header.Checksum));
+  PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) OemId:           '%c%c%c%c%c%c'\n",
+              PmttTable->Header.OemId[0], PmttTable->Header.OemId[1], PmttTable->Header.OemId[2],
+              PmttTable->Header.OemId[3], PmttTable->Header.OemId[4], PmttTable->Header.OemId[5]));
+  PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) OemTableId:      0x%08X\n", PmttTable->Header.OemTableId));
+  PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) OemRevision:     %d\n", PmttTable->Header.OemRevision));
+  PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) CreatorId:       0x%08X\n", PmttTable->Header.CreatorId));
+  PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) CreatorRevision: %d\n", PmttTable->Header.OemRevision));
+  PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) NumOfMemoryDevices: %d\n", PmttTable->NumOfMemoryDevices));
+
+  PMTTDEBUG ((DEBUG_INFO, "\n"));
+  for (Socket = 0; Socket < NELEMENTS (PmttTable->Socket); Socket++) {
+
+    PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d] Type:        0x%02X\n", Socket, PmttTable->Socket[Socket].Type));
+    PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d] Length:      %d\n", Socket, PmttTable->Socket[Socket].Length));
+    PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d] Flags:       0x%04X\n", Socket, PmttTable->Socket[Socket].Flag));
+    PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d] SocketId:    %d\n", Socket, PmttTable->Socket[Socket].SckIdent));
+    PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d] NumOfMemoryDevices:    %d\n", Socket, PmttTable->Socket[Socket].NumOfMemoryDevices));
+
+    PMTTDEBUG ((DEBUG_INFO, "\n"));
+    for (Die = 0; Die < NELEMENTS(PmttTable->Socket[Socket].Die); Die++) {
+
+      PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d] Type:        0x%02X\n", Socket, Die, PmttTable->Socket[Socket].Die[Die].Type));
+      PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d] Length:      %d\n", Socket, Die, PmttTable->Socket[Socket].Die[Die].Length));
+      PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d] Flags:       0x%04X\n", Socket, Die, PmttTable->Socket[Socket].Die[Die].Flag));
+      PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d] DieId:       %d\n", Socket, Die, PmttTable->Socket[Socket].Die[Die].DieId));
+      PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d] TypeUuid:    %g\n", Socket, Die, PmttTable->Socket[Socket].Die[Die].TypeUuid));
+      PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d] NumOfMemoryDevices:       %d\n", Socket, Die, PmttTable->Socket[Socket].Die[Die].NumOfMemoryDevices));
+
+      PMTTDEBUG ((DEBUG_INFO, "\n"));
+      for (Imc = 0; Imc < NELEMENTS(PmttTable->Socket[Socket].Die[Die].Imc); Imc++) {
+
+        PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d] Type:                   0x%02X\n", Socket, Die, Imc, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Type));
+        PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d] Length:                 %d\n", Socket, Die, Imc, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Length));
+        PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d] Flags:                  0x%04X\n", Socket, Die, Imc, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Flag));
+        PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d] ImcId:                  %d\n", Socket, Die, Imc, PmttTable->Socket[Socket].Die[Die].Imc[Imc].ImcId));
+        PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d] NumOfMemoryDevices:     %d\n", Socket, Die, Imc, PmttTable->Socket[Socket].Die[Die].Imc[Imc].NumOfMemoryDevices));
+
+        PMTTDEBUG ((DEBUG_INFO, "\n"));
+        for (Channel = 0; Channel < NELEMENTS(PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel); Channel++) {
+
+          PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d] Type:                   0x%02X\n", Socket, Die, Imc, Channel, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Type));
+          PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d] Length:                 %d\n", Socket, Die, Imc, Channel, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Length));
+          PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d] Flags:                  0x%04X\n", Socket, Die, Imc, Channel, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Flag));
+          PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d] ChannelId:              %d\n", Socket, Die, Imc, Channel, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].ChannelId));
+          PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d] TypeUuid:               %g\n", Socket, Die, Imc, Channel, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].TypeUuid));
+          PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d] NumOfMemoryDevices:     %d\n", Socket, Die, Imc, Channel, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].NumOfMemoryDevices));
+
+          PMTTDEBUG ((DEBUG_INFO, "\n"));
+          for (Dimm = 0; Dimm < NELEMENTS(PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot); Dimm++) {
+
+            PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d] Type:                   0x%02X\n", Socket, Die, Imc, Channel, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Type));
+            PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d] Length:                 %d\n", Socket, Die, Imc, Channel, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Length));
+            PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d] Flags:                  0x%04X\n", Socket, Die, Imc, Channel, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Flag));
+            PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d] SlotId:                 %d\n", Socket, Die, Imc, Channel, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].SlotId));
+            PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d] TypeUuid:               %g\n", Socket, Die, Imc, Channel, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].TypeUuid));
+            PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d] NumOfMemoryDevices:     %d\n", Socket, Die, Imc, Channel, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].NumOfMemoryDevices));
+
+            PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d][%d] Type:                0x%02X\n", Socket, Die, Imc, Channel, Dimm, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Type));
+            PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d][%d] Length:              %d\n", Socket, Die, Imc, Channel, Dimm, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Length));
+            PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d][%d] Flags:               0x%04X\n", Socket, Die, Imc, Channel, Dimm, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Flag));
+            PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d][%d] SmbiosHandle:        0x%08X\n", Socket, Die, Imc, Channel, Dimm, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.SmbiosHandle));
+            PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d][%d] NumOfMemoryDevices:  %d\n", Socket, Die, Imc, Channel, Dimm, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.NumOfMemoryDevices));
+          } // for (Dimm...)
+        } // for (Channel...)
+      } // for (Imc...)
+    } // for (Die...)
+  } // for (Skt...)
+  return EFI_SUCCESS;
+} // PatchPlatformMemoryTopologyTable ()

+ 1153 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSlit.c

@@ -0,0 +1,1153 @@
+/** @file
+  ACPI Platform Driver Hooks
+
+  @copyright
+  Copyright 1996 - 2020 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include "AcpiPlatformLibLocal.h"
+
+extern SYSTEM_MEMORY_MAP_HOB        *mSystemMemoryMap;
+extern EFI_IIO_UDS_PROTOCOL         *mIioUds;
+extern EFI_ACPI_TABLE_PROTOCOL      *mAcpiTable;
+extern CPU_CSR_ACCESS_VAR           *mCpuCsrAccessVarPtr;
+
+EFI_ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE_PMEM_INFO mSlitPmemInfo[EFI_ACPI_SLIT_PMEM_INFO_CNT];
+
+
+/**
+  Displays System Locality Distance Information Table (SLIT)
+
+  @param None
+
+  @retval None
+**/
+VOID
+DisplayEntries (
+  IN ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitPtr
+  )
+{
+  UINT16                                     EntryIdx = 0;
+  UINT16                                     MaxTableEntries;
+  UINT8                                      NodeCount;
+
+  if (SlitPtr == NULL) {
+
+    ASSERT (SlitPtr != NULL);
+    return;
+  }
+  NodeCount = (UINT8)SlitPtr->Header.NumberOfSystemLocalities;
+  MaxTableEntries = NodeCount * NodeCount;
+
+  DEBUG ((DEBUG_INFO, "SLIT: Dump table (size %d):\n", NodeCount));
+
+  while (EntryIdx < MaxTableEntries) {
+
+    DEBUG ((DEBUG_INFO, "%02X ", SlitPtr->NumSlit[EntryIdx].Entry));
+    if ((EntryIdx % NodeCount) == (NodeCount - 1)) {
+      DEBUG ((DEBUG_INFO, "\n"));
+    }
+    EntryIdx++;
+  }
+}
+
+
+/**
+  Stores correlation between AEP PMEM NUMA node and socket
+
+  @param[in] Pmem   AEP PMEM NUMA node number
+  @param[in] Socket Socket number
+
+  @retval None
+
+**/
+VOID
+SavePmemInfo (
+  IN UINT8 Pmem,
+  IN UINT8 Socket,
+  MEM_TYPE Type
+  )
+{
+  if (Pmem < EFI_ACPI_SLIT_PMEM_INFO_CNT) {
+
+    DEBUG ((DEBUG_INFO, "SLIT: Found PMem %d at socket %d (mem type 0x%X)\n", Pmem, Socket, Type));
+    mSlitPmemInfo[Pmem].Pmem = Pmem;
+    mSlitPmemInfo[Pmem].Socket = Socket;
+    mSlitPmemInfo[Pmem].Valid = TRUE;
+    return;
+  }
+
+  DEBUG ((DEBUG_ERROR, "SLIT: Error - Number of PMem nodes (%d) exceed PMem info data table size (%d)\n",
+      Pmem, EFI_ACPI_SLIT_PMEM_INFO_CNT));
+  ASSERT (FALSE);
+}
+
+/**
+  Retrieves socket correlated with given AEP PMEM NUMA node
+
+  @param[in] Pmem AEP PMEM Numa node
+
+  @retval Socket correlated with given AEP PMEM NUMA node
+
+**/
+UINT8
+GetSocketForPmem (
+  IN UINT8 Pmem
+  )
+{
+  UINT8 PmemInfoEntry;
+
+  for (PmemInfoEntry = 0; PmemInfoEntry < EFI_ACPI_SLIT_PMEM_INFO_CNT; PmemInfoEntry++) {
+    if (mSlitPmemInfo[PmemInfoEntry].Valid && mSlitPmemInfo[PmemInfoEntry].Pmem == Pmem) {
+      return mSlitPmemInfo[PmemInfoEntry].Socket;
+    }
+  }
+
+  DEBUG ((DEBUG_ERROR, "SLIT: Error - PMem node (%d) is not associated with any socket\n", Pmem));
+  ASSERT (FALSE);
+  return PMEM_INVALID_SOCKET;
+}
+
+/**
+  This function gets the physical node index for given FPGA NUMA node.
+  If the given FPGA NUMA node doesn't exist, an invalid physical node
+  index 0xff will be returned.
+
+  @param[in] FpgaNumaNodeId      FPGA NUMA node index (0 based).
+
+  @retval Physical node index of given FPGA NUMA node (0 based).
+
+**/
+UINT8
+GetPhyNodeIdForFpga (
+  IN UINT8  FpgaNumaNodeId
+  )
+{
+  UINT32    FpgaPresentBitMap;
+  UINT8     PhyNodeId;
+
+  PhyNodeId = 0;
+  FpgaPresentBitMap = mCpuCsrAccessVarPtr->FpgaPresentBitMap;
+
+  while ((FpgaNumaNodeId != (UINT8) -1) && (FpgaPresentBitMap != 0)) {
+    if ((FpgaPresentBitMap & BIT0) != 0) {
+      FpgaNumaNodeId--;
+    }
+    FpgaPresentBitMap >>= 1;
+    PhyNodeId++;
+  }
+
+  if ((FpgaPresentBitMap == 0) && (FpgaNumaNodeId != (UINT8) -1)) {
+    return (UINT8) -1;
+  }
+
+  return PhyNodeId - 1;
+}
+
+/**
+  Retrieves number of FPGA Presents
+
+  @retval Number of FPGA Presents in the system
+
+**/
+UINT8
+GetFpgaCount (
+  VOID)
+{
+  UINT8   FpgaCount = 0;
+  UINT32  FpgaPresentBitMap = mCpuCsrAccessVarPtr->FpgaPresentBitMap;
+
+  while (FpgaPresentBitMap) {
+    if (FpgaPresentBitMap & BIT0) {
+      FpgaCount++;
+    }
+    FpgaPresentBitMap >>= 1;
+  }
+  return FpgaCount;
+}
+
+/**
+  Retrieves number of AEP PMEM NUMA nodes
+
+  @retval Number of AEP PMEM NUMA nodes
+
+**/
+UINT8
+GetPmemNodeCount (
+  VOID
+  )
+{
+  UINT8 Socket;
+  UINT8 SadRule;
+  UINT8 PmemNodeCount = 0;
+
+  EFI_STATUS                  Status = EFI_SUCCESS;
+  DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return 0;
+  }
+
+  for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+    if ((mCpuCsrAccessVarPtr->socketPresentBitMap & (BIT0 << Socket)) == 0) {
+      continue;
+    }
+    for (SadRule = 0; SadRule < MAX_SAD_RULES; SadRule++) {
+      //
+      // Only local SADs of PMEM type should be taken into consideration.
+      // Skip any memory region marked reserved.
+      //
+      if (mSystemMemoryMap->Socket[Socket].SAD[SadRule].local &&
+          DynamicSiLibraryProtocol2->IsMemTypeAppDirect (mSystemMemoryMap->Socket[Socket].SAD[SadRule].type) &&
+          !DynamicSiLibraryProtocol2->IsMemTypeReserved (mSystemMemoryMap->Socket[Socket].SAD[SadRule].type)) {
+
+        SavePmemInfo (PmemNodeCount++, Socket, mSystemMemoryMap->Socket[Socket].SAD[SadRule].type);
+      }
+    }
+  }
+
+  return PmemNodeCount;
+}
+
+/**
+  Retrieves number of clusters in the system if system is in SNC mode. If system is not
+  in SNC mode, the return 1.
+
+  @return Number of clusters in the system in SNC mode or 1 if system is not in SNC mode.
+
+**/
+UINT8
+GetNumClusters (
+  VOID
+  )
+{
+  UINT8 NumClusters;
+
+  NumClusters = mIioUds->IioUdsPtr->SystemStatus.OutNumOfCluster;
+  if ((NumClusters == 0) || (mIioUds->IioUdsPtr->SystemStatus.OutSncEn == 0)) {
+    NumClusters = 1; // For non-SNC mode, we should also return 1.
+  }
+  if (mSystemMemoryMap->VirtualNumaEnable) {
+    NumClusters = NumClusters * mSystemMemoryMap->VirtualNumOfCluster;
+  }
+
+  return NumClusters;
+}
+
+/**
+  Retrieves number of enabled CPUs in the system
+
+  @param None
+
+  @retval Number of enabled CPUs in the system
+
+**/
+UINT8
+GetNumCpus (
+  VOID
+  )
+{
+  return mIioUds->IioUdsPtr->SystemStatus.numCpus;
+}
+
+/**
+  Calculates total number of nodes
+
+  @param[in]      NumCpus       Number of CPUs
+  @param[in]      NumClusters   Number of clusters
+  @param[in]      PmemNodeCount Number of AEP PMEM NUMA nodes
+
+  @retval Total number of nodes
+
+**/
+UINT8
+GetNodeCount (
+  IN UINT8  NumCpus,
+  IN UINT8  NumClusters,
+  IN UINT8  PmemNodeCount,
+  IN UINT8 FpgaCount
+  )
+{
+  UINT8 NodeCount;
+
+  if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_MIX_1LM2LM) {
+    NodeCount = ((NumCpus * NumClusters * EFI_ACPI_SLIT_DOMAINS_NODES_MAX_CNT) + PmemNodeCount + FpgaCount);
+  } else {
+    NodeCount = ((NumCpus * NumClusters) + PmemNodeCount + FpgaCount);
+  }
+  if ((NodeCount * NodeCount) < EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT) {
+    return NodeCount;
+  }
+
+  DEBUG ((DEBUG_ERROR, "SLIT: Error - Nodes distances info data size (%d) exceed SLIT distances info table size (%d)\n",
+    (NodeCount * NodeCount), EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Verifies whether sockets are linked
+
+  @param[in]      SourceSocket  Source Socket ID
+  @param[in]      TargetSocket  Targer Socket ID
+
+  @retval TRUE link between source socket and target socket was found
+          FALSE otherwise
+
+**/
+BOOLEAN
+SocketsLinked (
+  IN UINT32  SourceSocket,
+  IN UINT32  TargetSocket
+  )
+{
+  UINT8 PeerSocket;
+  UINT8 LinkValid;
+  UINT8 PeerSocId;
+
+  EFI_STATUS                  Status = EFI_SUCCESS;
+  DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return FALSE;
+  }
+
+  //
+  // Validate sockets ids
+  //
+  if ((SourceSocket < MAX_SOCKET) && (TargetSocket < MAX_SOCKET)) {
+    //
+    // Do not process when source socket is the same as target socket
+    //
+    if (SourceSocket != TargetSocket) {
+      for (PeerSocket = 0; PeerSocket < (DynamicSiLibraryProtocol2->GetKtiPortCnt()); PeerSocket++) {
+        LinkValid = mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[SourceSocket].PeerInfo[PeerSocket].Valid;
+        PeerSocId = mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[SourceSocket].PeerInfo[PeerSocket].PeerSocId;
+        if (LinkValid && (PeerSocId == TargetSocket)) {
+          //
+          // Link found
+          //
+          return TRUE;
+        }
+      }
+    }
+    //
+    // Link not found
+    //
+    return FALSE;
+  }
+
+  DEBUG ((DEBUG_ERROR, "SLIT: Error when checking if sockets are linked (source socket id %d, target socket id %d)\n", SourceSocket, TargetSocket));
+  return FALSE;
+}
+
+/**
+  Initializes SLIT Table entries
+
+  @param[in,out] Table Pointer to SLIT ACPI tables
+
+  @retval EFI_SUCCESS  operation completed successfully
+
+**/
+EFI_STATUS
+InitEntries (
+  IN OUT ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitPtr
+  )
+{
+  if (SlitPtr == NULL) {
+    ASSERT (SlitPtr != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+  SetMem (&SlitPtr->NumSlit[0].Entry, EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT, 0xFF);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Processes socket nodes
+
+  @param[in,out]  Table         Pointer to SLIT ACPI tables
+  @param[in]      NumCpus       Number of CPUs
+  @param[in]      NumClusters   Number of clusters
+  @param[in]      PmemNodeCount Number of AEP PMEM NUMA nodes
+  @param[in]      FpgaCount     Number of FPGA NUMA nodes
+  @param[in]      NodeCount     Number of all nodes
+
+  @retval EFI_SUCCESS  operation completed successfully
+
+**/
+EFI_STATUS
+ProcessSockets (
+  IN OUT EFI_ACPI_COMMON_HEADER *Table,
+  IN UINT8                      NumCpus,
+  IN UINT8                      NumClusters,
+  IN UINT8                      PmemNodeCount,
+  IN UINT8                      FpgaCount,
+  IN UINT8                      NodeCount
+  )
+{
+  ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE  *SlitAcpiTable;
+  UINT16                                  EntryIdx;
+  UINT8                                   SourceNode;
+  UINT8                                   SourceSocket;
+  UINT8                                   SourceCluster;
+  UINT8                                   TargetSocket;
+  UINT8                                   TargetCluster;
+  UINT8                                   VirtualNumaFactor;
+
+  if (NULL == Table) {
+    DEBUG ((DEBUG_ERROR, "SLIT: Error in SLIT update with data about nodes on same socket\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+  VirtualNumaFactor = 1;
+  if (mSystemMemoryMap->VirtualNumaEnable) {
+    VirtualNumaFactor = mSystemMemoryMap->VirtualNumOfCluster;
+  }
+
+  DEBUG ((DEBUG_INFO, "SLIT: Update with data about nodes on same socket\n"));
+
+  SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
+
+  for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount) ; SourceNode++) {
+    SourceSocket = SourceNode / NumClusters;
+    SourceCluster = SourceNode % NumClusters;
+    for (TargetSocket = 0; TargetSocket < NumCpus; TargetSocket++) {
+      for (TargetCluster = 0; TargetCluster < NumClusters; TargetCluster++) {
+        if (SourceSocket == TargetSocket) {
+          EntryIdx = (SourceNode * (NodeCount)) + (TargetSocket * NumClusters) + TargetCluster;
+          //
+          // Source and target are nodes on same socket
+          //
+          if ((SourceCluster / VirtualNumaFactor) == (TargetCluster / VirtualNumaFactor)) {
+            //
+            // a) Same socket same physical cluster
+            //
+            SlitAcpiTable->NumSlit[EntryIdx].Entry = ZERO_HOP;
+          } else {
+            //
+            // b) Same socket different cluster
+            //
+            SlitAcpiTable->NumSlit[EntryIdx].Entry = ZERO_ONE;
+          }
+        }
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Processes socket nodes
+
+  @param[in,out]  Table         Pointer to SLIT ACPI tables
+  @param[in]      NumCpus       Number of CPUs
+  @param[in]      NumClusters   Number of clusters
+  @param[in]      PmemNodeCount Number of AEP PMEM NUMA nodes
+  @param[in]      FpgaCount     Number of FPGA NUMA nodes
+  @param[in]      NodeCount     Number of all nodes
+
+  @retval EFI_SUCCESS  operation completed successfully
+
+**/
+EFI_STATUS
+ProcessMixedModeSockets (
+  IN OUT EFI_ACPI_COMMON_HEADER *Table,
+  IN UINT8                      NumCpus,
+  IN UINT8                      NumClusters,
+  IN UINT8                      PmemNodeCount,
+  IN UINT8                      FpgaCount,
+  IN UINT8                      NodeCount
+  )
+{
+  ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE  *SlitAcpiTable;
+  UINT16                                  EntryIdx1LM;
+  UINT16                                  EntryIdx2LM;
+  UINT8                                   SourceNode;
+  UINT8                                   SourceSocket;
+  UINT8                                   SourceCluster;
+  UINT8                                   TargetSocket;
+  UINT8                                   TargetCluster;
+  BOOLEAN                                 Is2LM;
+
+  if (NULL == Table) {
+    DEBUG ((DEBUG_ERROR, "SLIT: Error in SLIT update with data about nodes on same socket for Mixed Mode\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((DEBUG_INFO, "SLIT: Update with data about nodes on same socket for Mixed Mode\n"));
+
+  SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
+
+  for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount) ; SourceNode++) {
+    Is2LM = (SourceNode >= NumCpus * NumClusters) ? TRUE : FALSE;
+    SourceSocket = (SourceNode - NumCpus * NumClusters * (Is2LM ? 1 : 0)) / NumClusters;
+    SourceCluster = (SourceNode - NumCpus * NumClusters * (Is2LM ? 1 : 0)) % NumClusters;
+
+    TargetSocket = SourceSocket;
+    for (TargetCluster = 0; TargetCluster < NumClusters; TargetCluster++) {
+      EntryIdx1LM = (UINT16)((SourceNode * NodeCount) + (TargetSocket * NumClusters) + TargetCluster);
+      EntryIdx2LM = EntryIdx1LM + NumCpus * NumClusters;
+
+      if ((SourceCluster == TargetCluster) && (Is2LM == FALSE)) {
+        //
+        // CPU -> 1LM at the same socket, the same cluster
+        //
+        SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ZERO_HOP;
+        //
+        // CPU -> 2LM at the same socket, the same cluster
+        //
+        SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ZERO_ONE;
+      } else if ((SourceCluster == TargetCluster) && (Is2LM == TRUE)) {
+        //
+        // CPU -> 2LM at the same socket, the same cluster
+        //
+        SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ZERO_ONE;
+        //
+        // not effective
+        //
+        SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ZERO_HOP;
+      } else if ((SourceCluster != TargetCluster) && (Is2LM == FALSE)) {
+        //
+        // CPU -> 1LM at the same socket, different cluster
+        //
+        SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ZERO_ONE;
+        //
+        // CPU -> 2LM at the same socket, different cluster
+        //
+        SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ZERO_TWO;
+      } else {
+        //
+        // branch condition: ((SourceCluster != TargetCluster) && (Is2LM == TRUE))
+        // CPU -> 2LM at the same socket, different cluster
+        //
+        SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ZERO_TWO;
+        //
+        // not effective
+        //
+        SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ZERO_TWO;
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Processes connections between sockets to retrieve valid distances
+
+  @param[in,out]  Table         Pointer to SLIT ACPI tables
+  @param[in]      NumCpus       Number of CPUs
+  @param[in]      NumClusters   Number of clusters
+  @param[in]      PmemNodeCount Number of AEP PMEM NUMA nodes
+  @param[in]      FpgaCount     Number of FPGA NUMA nodes
+  @param[in]      NodeCount     Number of all nodes
+
+  @retval EFI_SUCCESS  operation completed successfully
+
+**/
+EFI_STATUS
+ProcessSocketsLinks (
+  IN OUT EFI_ACPI_COMMON_HEADER *Table,
+  IN UINT8                      NumCpus,
+  IN UINT8                      NumClusters,
+  IN UINT8                      PmemNodeCount,
+  IN UINT8                      FpgaCount,
+  IN UINT8                      NodeCount
+  )
+{
+  ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE  *SlitAcpiTable;
+  UINT8                                   SourceNode;
+  UINT8                                   SourceSocket;
+  UINT8                                   SourceCluster;
+  UINT8                                   TargetSocket;
+
+  if (NULL == Table) {
+    DEBUG ((DEBUG_ERROR, "SLIT: Error in processing links between sockets\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((DEBUG_INFO, "SLIT: Update table with links between sockets\n"));
+
+  SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
+
+  for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount); SourceNode++) {
+    SourceSocket = SourceNode / NumClusters;
+    SourceCluster = SourceNode % NumClusters;
+    for (TargetSocket = 0; TargetSocket < NumCpus; TargetSocket++) {
+      if (SocketsLinked (GetSocketPhysicalId (SourceSocket), GetSocketPhysicalId (TargetSocket))) {
+        SetMem (&SlitAcpiTable->NumSlit[(SourceNode * NodeCount) + (TargetSocket * NumClusters)].Entry,
+                NumClusters, ONE_HOP);
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Processes connections between sockets to retrieve valid distances
+
+  @param[in,out]  Table         Pointer to SLIT ACPI tables
+  @param[in]      NumCpus       Number of CPUs
+  @param[in]      NumClusters   Number of clusters
+  @param[in]      PmemNodeCount Number of AEP PMEM NUMA nodes
+  @param[in]      FpgaCount     Number of FPGA NUMA nodes
+  @param[in]      NodeCount     Number of all nodes
+
+  @retval EFI_SUCCESS  operation completed successfully
+
+**/
+EFI_STATUS
+ProcessMixedModeSocketsLinks (
+  IN OUT EFI_ACPI_COMMON_HEADER *Table,
+  IN UINT8                      NumCpus,
+  IN UINT8                      NumClusters,
+  IN UINT8                      PmemNodeCount,
+  IN UINT8                      FpgaCount,
+  IN UINT8                      NodeCount
+  )
+{
+  ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE  *SlitAcpiTable;
+  UINT16                                  EntryIdx1LM;
+  UINT16                                  EntryIdx2LM;
+  UINT8                                   SourceNode;
+  UINT8                                   SourceSocket;
+  UINT8                                   SourceCluster;
+  UINT8                                   TargetSocket;
+  UINT8                                   TargetCluster;
+  BOOLEAN                                 Is2LM;
+
+  if (NULL == Table) {
+    DEBUG ((DEBUG_ERROR, "SLIT: Error in processing links between sockets in Mixed Mode\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((DEBUG_INFO, "SLIT: Update table with links between sockets in Mixed Mode\n"));
+
+  SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
+
+  for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount); SourceNode++) {
+    Is2LM = (SourceNode >= NumCpus * NumClusters) ? TRUE : FALSE;
+    SourceSocket = (SourceNode - NumCpus * NumClusters * (Is2LM ? 1 : 0)) / NumClusters;
+    SourceCluster = (SourceNode - NumCpus * NumClusters * (Is2LM ? 1 : 0)) % NumClusters;
+
+    for (TargetSocket = 0; TargetSocket < NumCpus; TargetSocket++) {
+      if (SocketsLinked (GetSocketPhysicalId (SourceSocket), GetSocketPhysicalId (TargetSocket))) {
+        //
+        // If both sockets are linked by KTI and not the same socket.
+        //
+        for (TargetCluster = 0; TargetCluster < NumClusters; TargetCluster++) {
+          EntryIdx1LM = (UINT16)((SourceNode * NodeCount) + (TargetSocket * NumClusters) + TargetCluster);
+          EntryIdx2LM = EntryIdx1LM + NumCpus * NumClusters;
+
+          if (Is2LM == FALSE) {
+            //
+            // CPU -> 1LM at different socket
+            //
+            SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ONE_HOP;
+            //
+            // CPU -> 2LM at different socket
+            //
+            SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ONE_ONE;
+          } else {
+            //
+            // branch condition: (Is2LM == TRUE)
+            // CPU -> 2LM at different socket
+            //
+            SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ONE_ONE;
+            //
+            // not effective
+            //
+            SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ONE_TWO;
+          }
+        }
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Processes all AEP PMEM NUMA nodes
+
+  @param[in,out]  Table         Pointer to SLIT ACPI tables
+  @param[in]      NumCpus       Number of CPUs
+  @param[in]      NumClusters   Number of clusters
+  @param[in]      PmemNodeCount Number of AEP PMEM NUMA nodes
+  @param[in]      FpgaCount     Number of FPGA NUMA nodes
+  @param[in]      NodeCount     Number of all nodes
+
+  @retval EFI_SUCCESS  operation completed successfully
+
+**/
+EFI_STATUS
+ProcessPmems (
+  IN OUT EFI_ACPI_COMMON_HEADER *Table,
+  IN UINT8                      NumCpus,
+  IN UINT8                      NumClusters,
+  IN UINT8                      PmemNodeCount,
+  IN UINT8                      FpgaCount,
+  IN UINT8                      NodeCount
+  )
+{
+  ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE  *SlitAcpiTable;
+  UINT16                                  EntryIdx;
+  UINT8                                   SourceNode;
+  UINT8                                   TargetNode;
+  UINT8                                   SourceSocket;
+  UINT8                                   TargetCluster;
+  UINT8                                   TargetSocket;
+  UINT8                                   SourcePmem;
+  UINT8                                   TargetPmem;
+  UINT8                                   SourcePmemSocket;
+  UINT8                                   TargetPmemSocket;
+  UINT8                                   TotalVolMemNodes;
+
+  if (NULL == Table) {
+    DEBUG ((DEBUG_ERROR, "SLIT: Error in processing PMems\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_MIX_1LM2LM) {
+    TotalVolMemNodes = NumCpus * NumClusters * EFI_ACPI_SLIT_DOMAINS_NODES_MAX_CNT;
+  } else {
+    TotalVolMemNodes = NumCpus * NumClusters;
+  }
+
+  DEBUG ((DEBUG_INFO, "SLIT: Include PMem NUMA nodes\n"));
+
+  if (PmemNodeCount > 0) {
+
+    SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
+
+    //
+    // 1) AEP PMEM nodes to AEP PMEM nodes distances
+    //
+    for (SourceNode = (NodeCount - PmemNodeCount - FpgaCount); SourceNode < (NodeCount - FpgaCount); SourceNode++) {
+      SourcePmem = SourceNode - TotalVolMemNodes;
+      for (TargetPmem = 0; TargetPmem < PmemNodeCount; TargetPmem++) {
+        TargetNode = TargetPmem + TotalVolMemNodes;
+        EntryIdx = (SourceNode * NodeCount) + TargetNode;
+        if (SourcePmem == TargetPmem) {
+          SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ZERO_HOP;
+        } else {
+          //
+          // Retrieve sockets associated with PMEMs
+          //
+          SourcePmemSocket = GetSocketForPmem (SourcePmem);
+          TargetPmemSocket = GetSocketForPmem (TargetPmem);
+
+          if (SourcePmemSocket == TargetPmemSocket) {
+            //
+            // PMEMs are on the same socket
+            //
+            SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_ONE;
+          } else {
+            //
+            // Assign 2 hop and process with PeerInfo checking
+            //
+            SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_TWO_HOP;
+
+            //
+            // Examine PeerInfo to look for link between AEP PMEM source socket and AEP PMEM target socket
+            //
+            if (SocketsLinked (SourcePmemSocket, TargetPmemSocket)) {
+              //
+              // Link found assign 1 hop
+              //
+              SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_HOP;
+            }
+          }
+        }
+      }
+    }
+
+    //
+    // 2) Sockets to AEP PMEM nodes distances
+    //
+    for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount); SourceNode++) {
+      SourceSocket = GetSocketPhysicalId (SourceNode / NumClusters);
+      for (TargetPmem = 0; TargetPmem < PmemNodeCount; TargetPmem++) {
+        TargetPmemSocket = GetSocketForPmem (TargetPmem);
+        TargetNode = TargetPmem + TotalVolMemNodes;
+        EntryIdx = (SourceNode * NodeCount) + TargetNode;
+        if (SourceSocket == TargetPmemSocket) {
+          SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_ONE;
+        } else {
+          //
+          // Assign 2 hop and process with PeerInfo checking
+          //
+          SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_TWO_HOP;
+
+          //
+          // Examine PeerInfo to look for link between source socket and AEP PMEM socket
+          //
+          if (SocketsLinked (SourceSocket, TargetPmemSocket)) {
+            //
+            // Link found assign 1 hop
+            //
+            SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_HOP;
+          }
+        }
+      }
+    }
+
+    //
+    // 3) AEP PMEM nodes to sockets distances
+    //
+    for (SourceNode = (NodeCount - PmemNodeCount - FpgaCount); SourceNode < (NodeCount - FpgaCount); SourceNode++) {
+      SourcePmem = SourceNode - TotalVolMemNodes;
+      SourcePmemSocket = GetSocketForPmem (SourcePmem);
+      for (TargetSocket = 0; TargetSocket < NumCpus; TargetSocket++) {
+        for (TargetCluster = 0; TargetCluster < NumClusters; TargetCluster++) {
+          EntryIdx = (SourceNode * NodeCount) + (TargetSocket * NumClusters) + TargetCluster;
+          if(SourcePmemSocket == GetSocketPhysicalId (TargetSocket)) {
+            SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_ONE;
+          } else {
+            //
+            // Assign 2 hop and process with PeerInfo checking
+            //
+            SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_TWO_HOP;
+
+            //
+            // Examine PeerInfo to look for link between source socket and AEP PMEM socket
+            //
+            if (SocketsLinked (SourcePmemSocket, GetSocketPhysicalId (TargetSocket))) {
+              //
+              // Link found assign 1 hop
+              //
+              SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_HOP;
+            }
+          }
+        }
+      }
+    }
+  } else {
+    DEBUG ((DEBUG_INFO, "SLIT: PMem NUMA nodes not present\n"));
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function processes all FPGA NUMA nodes.
+
+  @param[in,out] Table             Pointer to SLIT ACPI tables.
+  @param[in] NumClusters           Number of clusters.
+  @param[in] PmemNodeCount         Number of AEP PMEM NUMA nodes.
+  @param[in] FpgaCount             Number of FPGA NUMA nodes.
+  @param[in] NodeCount             Number of all nodes.
+
+  @retval EFI_SUCCESS              This function is executed successfully.
+  @retval EFI_INVALID_PARAMETER    Some of input parameters are invalid.
+**/
+EFI_STATUS
+ProcessFpgaNodes (
+  IN OUT EFI_ACPI_COMMON_HEADER *Table,
+  IN UINT8                      NumClusters,
+  IN UINT8                      PmemNodeCount,
+  IN UINT8                      FpgaCount,
+  IN UINT8                      NodeCount
+  )
+{
+  ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE  *SlitAcpiTable;
+  UINT8                                   SourceNode;
+  UINT8                                   TargetNode;
+  UINT8                                   SourceSocket;
+  UINT8                                   TargetSocket;
+
+  if (Table == NULL) {
+    DEBUG ((DEBUG_ERROR, "SLIT: Error in processing FPGA nodes\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (FpgaCount == 0) {
+    return EFI_SUCCESS;
+  }
+
+  SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
+
+  for (SourceNode = (NodeCount - FpgaCount); SourceNode < NodeCount; SourceNode++) {
+    SourceSocket = GetPhyNodeIdForFpga (SourceNode - (NodeCount - FpgaCount));
+
+    for (TargetNode = 0; TargetNode < NodeCount; TargetNode++) {
+      if (TargetNode < (NodeCount- PmemNodeCount - FpgaCount)) {
+        TargetSocket = GetSocketPhysicalId (TargetNode / NumClusters);             // Normal nodes
+      } else if (TargetNode < (NodeCount - FpgaCount)) {
+        TargetSocket = GetSocketForPmem (TargetNode - (NodeCount - PmemNodeCount - FpgaCount));  // PMEM nodes
+      } else {
+        TargetSocket = GetPhyNodeIdForFpga (TargetNode - (NodeCount - FpgaCount)); // FPGA nodes
+      }
+
+      if (SourceSocket == TargetSocket) {
+        SlitAcpiTable->NumSlit[SourceNode * NodeCount + TargetNode].Entry = ZERO_HOP;
+      } else if (SocketsLinked (SourceSocket, TargetSocket)) {
+        SlitAcpiTable->NumSlit[SourceNode * NodeCount + TargetNode].Entry = ONE_HOP;
+        SlitAcpiTable->NumSlit[TargetNode * NodeCount + SourceNode].Entry = ONE_HOP;
+      } else {
+        SlitAcpiTable->NumSlit[SourceNode * NodeCount + TargetNode].Entry = TWO_HOP;
+        SlitAcpiTable->NumSlit[TargetNode * NodeCount + SourceNode].Entry = TWO_HOP;
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Processes all remaining valid SLIT nodes
+
+  @param[in,out] Table  pointer to SLIT ACPI tables
+
+  @retval EFI_SUCCESS  operation completed successfully
+
+**/
+EFI_STATUS
+ProcessRemainingNodes (
+  IN OUT EFI_ACPI_COMMON_HEADER *Table
+  )
+{
+  ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE  *SlitAcpiTable;
+  UINT16                                  EntryIdx = 0;
+  UINT16                                  MaxTableEntries;
+  UINT8                                   NodeCount;
+
+  if (NULL == Table) {
+    DEBUG ((DEBUG_ERROR, "SLIT: Error while processing remaining valid nodes\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((DEBUG_INFO, "SLIT: Fill in the rest of the SLIT table\n"));
+
+  SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
+
+  NodeCount = (UINT8)SlitAcpiTable->Header.NumberOfSystemLocalities;
+  MaxTableEntries = NodeCount * NodeCount;
+
+  while (EntryIdx < MaxTableEntries) {
+    if (SlitAcpiTable->NumSlit[EntryIdx].Entry == 0xFF) {
+      //
+      // This entry has not been filled yet, assign 2 hop to this table entry
+      //
+      SlitAcpiTable->NumSlit[EntryIdx].Entry = TWO_HOP;
+    }
+
+    if ((EntryIdx % NodeCount) == 0) {
+      DEBUG ((DEBUG_INFO, "[%2d - %2d] ", EntryIdx/NodeCount, EntryIdx%NodeCount));
+    }
+    EntryIdx++;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Processes unused SLIT nodes
+
+  @param[in,out] Table  pointer to SLIT ACPI tables
+
+  @retval EFI_SUCCESS  operation completed successfully
+
+**/
+EFI_STATUS
+ProcessUnusedNodes (
+  IN OUT EFI_ACPI_COMMON_HEADER *Table
+  )
+{
+  ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE  *SlitAcpiTable;
+  UINT16                                  MaxTableEntries;
+  UINT8                                   NodeCount;
+
+  if (NULL == Table) {
+    DEBUG ((DEBUG_ERROR, "SLIT: Error while processing unused nodes\n"));
+    return EFI_INVALID_PARAMETER;
+
+  }
+
+  DEBUG ((DEBUG_INFO, "SLIT: Zero out the unused nodes\n"));
+
+  SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
+
+  NodeCount = (UINT8)SlitAcpiTable->Header.NumberOfSystemLocalities;
+  MaxTableEntries = NodeCount * NodeCount;
+
+  SetMem (&SlitAcpiTable->NumSlit[MaxTableEntries],
+         (UINTN)&SlitAcpiTable->NumSlit[EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT] - (UINTN)&SlitAcpiTable->NumSlit[MaxTableEntries], 0);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Updates System Locality Distance Information Table (SLIT)
+
+  @param[in,out] Table  pointer to SLIT ACPI tables
+
+  @retval EFI_SUCCESS  operation completed successfully
+  @retval EFI_ABORTED  operation not completed due to processing error
+
+**/
+EFI_STATUS
+PatchSLitTable (
+   IN OUT EFI_ACPI_COMMON_HEADER  *Table
+   )
+{
+  ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE  *SlitAcpiTable;
+  EFI_STATUS                              Status;
+  UINT8                                   NodeCount;
+  UINT8                                   NumCpus;
+  UINT8                                   NumClusters;
+  UINT8                                   PmemNodeCount;
+  UINT8                                   FpgaCount;
+
+  NumCpus = GetNumCpus ();
+  NumClusters = GetNumClusters ();
+  PmemNodeCount = GetPmemNodeCount ();
+  FpgaCount = GetFpgaCount();
+  NodeCount = GetNodeCount (NumCpus, NumClusters, PmemNodeCount, FpgaCount);
+
+  DEBUG ((DEBUG_INFO, "SLIT: NumCpus %d, NumClusters %d, PmemNodeCount %d -> NodeCount %d FpgaCount %d\n",
+                             NumCpus, NumClusters, PmemNodeCount, NodeCount,FpgaCount));
+
+  SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
+  SlitAcpiTable->Header.NumberOfSystemLocalities = NodeCount;
+
+  //
+  // 1) Initialize all entries to 0xFF
+  //
+  Status = InitEntries (SlitAcpiTable);
+
+  //
+  // 2) Update SLIT table with data about nodes on same socket
+  //
+  if (!EFI_ERROR(Status)) {
+    if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_MIX_1LM2LM) {
+      Status = ProcessMixedModeSockets (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount);
+    } else {
+      Status = ProcessSockets (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount);
+    }
+  }
+
+  //
+  // 3) Update table with links between sockets by examining PeerInfo structure
+  //
+  if (!EFI_ERROR (Status)) {
+    if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_MIX_1LM2LM) {
+      Status = ProcessMixedModeSocketsLinks (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount);
+    } else {
+      Status = ProcessSocketsLinks (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount);
+    }
+  }
+
+  //
+  // 4) Update table with PMEMs
+  //
+  if (!EFI_ERROR (Status)) {
+    Status = ProcessPmems (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount);
+  }
+
+  //
+  // 5 Update table with FPGA
+  //
+  if (!EFI_ERROR (Status)) {
+    Status = ProcessFpgaNodes (Table, NumClusters, PmemNodeCount, FpgaCount, NodeCount);
+  }
+
+  //
+  // 6) Fill in the rest of the Slit table, 2 hops between any remaining valid nodes
+  //
+  if (!EFI_ERROR (Status)) {
+    Status = ProcessRemainingNodes (Table);
+  }
+
+  //
+  // 7) Zero out the unused nodes
+  //
+  if (!EFI_ERROR (Status)) {
+    Status = ProcessUnusedNodes (Table);
+  }
+
+  //
+  // 8) Print the entire SLIT table
+  //
+  if (!EFI_ERROR (Status)) {
+    DisplayEntries (SlitAcpiTable);
+  }
+
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  Allocate memory and fill SLIT information to this buffer, then
+  install this table to ACPI table.
+
+  @retval EFI_SUCCESS           Install table success.
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.
+
+**/
+EFI_STATUS
+InstallSlitTable (
+   VOID
+   )
+{
+  ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *Table;
+  UINTN                                  TableSize;
+  UINT8                                  NumClusters;
+  UINTN                                  TableHandle = 0;
+  EFI_STATUS                             Status;
+
+  NumClusters = GetNumClusters ();
+
+  TableSize = sizeof (EFI_ACPI_6_2_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER) +
+              sizeof (ACPI_SYSTEM_LOCALITIES_STRUCTURE) * EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT;
+
+  Table = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *) AllocateZeroPool (TableSize);
+  if (Table == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Table->Header.Header.Signature = EFI_ACPI_6_2_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE;
+  Table->Header.Header.Length = (UINT32) TableSize;
+  Table->Header.Header.Revision = EFI_ACPI_6_2_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_REVISION;
+  Table->Header.Header.OemRevision = EFI_ACPI_OEM_SLIT_REVISION;
+  CopyMem (Table->Header.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->Header.Header.OemId));
+  Table->Header.Header.OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+  Table->Header.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+  Table->Header.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+
+  //
+  // All node init with 0 before pass to patcher
+  //
+  PatchSLitTable ((EFI_ACPI_COMMON_HEADER *)&Table->Header.Header);
+
+  //
+  // Publish SLIT Structure to ACPI
+  //
+
+  Status = mAcpiTable->InstallAcpiTable (
+                          mAcpiTable,
+                          Table,
+                          Table->Header.Header.Length,
+                          &TableHandle
+                          );
+
+  //
+  // Free memory
+  //
+  if (Table != NULL) {
+    FreePool (Table);
+  }
+
+  return Status;
+}

+ 952 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSrat.c

@@ -0,0 +1,952 @@
+/** @file
+  ACPI Platform Driver Hooks
+
+  @copyright
+  Copyright 1996 - 2020 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include "AcpiPlatformLibLocal.h"
+#include <Library/CpuConfigLib.h>
+#include <IndustryStandard/Acpi.h>
+#include <Protocol/AcpiPlatformProtocol.h>
+#include <Library/MemTypeLib.h>
+
+extern BOOLEAN                      mX2ApicEnabled;
+extern struct SystemMemoryMapHob    *mSystemMemoryMap;
+extern EFI_IIO_UDS_PROTOCOL         *mIioUds;
+extern SOCKET_MEMORY_CONFIGURATION  mSocketMemoryConfiguration;
+extern UINT32                       mNumOfBitShift;
+extern UINT32                       mApicIdMap[MAX_SOCKET][MAX_CORE * MAX_THREAD];
+extern UINTN                        mNumberOfCPUs;
+extern CPU_ID_ORDER_MAP             mCpuApicIdOrderTable[];
+extern EFI_ACPI_TABLE_PROTOCOL      *mAcpiTable;
+extern CPU_CSR_ACCESS_VAR           *mCpuCsrAccessVarPtr;
+
+UINT32 mPackageChaTotal[MAX_SOCKET];
+
+CPU_LOGICAL_THREAD_ID_TABLE mCpuThreadIdMsrTable[MAX_CPU_NUM];
+
+static ACPI_PLATFORM_PROTOCOL   mAcpiPlatformProtocol;
+
+struct _ACPI_PLATFORM_UTILS_MEM_AFF_DATA {
+  EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE AcpiMemAffData[MEMORY_AFFINITY_STRUCTURE_COUNT];
+  BOOLEAN                                AcpiMemAffDataValid;
+} mAcpiPlatformMemAffData;
+
+
+VOID
+CollectThreadIdMsrData (
+  IN UINT8        SncEnabled,
+  IN UINT8        SncNumOfCluster
+  );
+
+UINT32
+GetProximityDomainForSNC (
+  UINT32 ApicId
+  );
+
+
+/**
+  This function counts the number of bits set in a 32-bit unsigned integer.
+
+  @param[in] Value     The 32-bit unsigned integer to count.
+
+  @retval The number of set bits.
+**/
+UINT8
+BitCount32 (
+  IN UINT32   Value
+  )
+{
+  UINT8    Count;
+
+  Count = 0;
+  while (Value != 0) {
+    Value &= Value - 1;
+    Count++;
+  }
+
+  return Count;
+}
+
+/**
+  Get the socket logical index.
+
+  This function convert the socket physical index to logical index (0 based).
+  If the specified physical socket is not enabled, an invalid logical index 0xff
+  will be returned. The socket physical index and logical index will be the same
+  if the indexes of enabled sockets are continuous.
+
+  @param[in] SocketPhysicalId    Socket physical index.
+
+  @retval Socket logical index.
+**/
+UINT8
+GetSocketLogicalId (
+  IN UINT8  SocketPhysicalId
+  )
+{
+  UINT32    SocketBitMap;
+
+  if ((mCpuCsrAccessVarPtr->socketPresentBitMap & (BIT0 << SocketPhysicalId)) == 0) {
+    return (UINT8) -1;
+  }
+
+  SocketBitMap = mCpuCsrAccessVarPtr->socketPresentBitMap & ((BIT0 << SocketPhysicalId) - 1);
+  return BitCount32 (SocketBitMap);
+}
+
+/**
+  Get the socket physical index.
+
+  This function convert the socket logical index to physical index (0 based).
+  If the specified logical socket does not exist, an invalid physical index 0xff
+  will be returned. The socket physical index and logical index will be the same
+  if the indexes of enabled sockets are continuous.
+
+  @param[in] SocketLogicalId    Socket logical index.
+
+  @retval Socket physical index.
+**/
+UINT8
+GetSocketPhysicalId (
+  IN UINT8  SocketlogicId
+  )
+{
+  UINT32    SocketBitMap;
+
+  SocketBitMap = mCpuCsrAccessVarPtr->socketPresentBitMap;
+
+  while (SocketlogicId != 0) {
+    SocketBitMap &= SocketBitMap - 1;
+    SocketlogicId--;
+  }
+
+  if (SocketBitMap == 0) {
+    return (UINT8) -1;
+  }
+
+  return BitCount32 (SocketBitMap ^ (SocketBitMap - 1)) - 1;
+}
+
+/**
+
+    Update the SRAT APIC IDs.
+
+    @param *SRAAcpiTable   - The table to be set
+
+    @retval EFI_SUCCESS -  Returns Success
+
+**/
+EFI_STATUS
+PatchSratAllApicIds(
+   IN OUT   STATIC_RESOURCE_AFFINITY_TABLE  *SRAAcpiTable
+   )
+{
+  UINT16                      ThreadIndex;   // Support more than 256 threads (8S case)
+  UINT8                       *ApicTablePtr;
+  UINT8                       socket;
+  UINT8                       Index;
+
+  ThreadIndex = 0;
+  for (socket = 0; socket < MAX_SOCKET; socket++) {
+    ApicTablePtr = (UINT8*)mApicIdMap[socket];
+    //
+    // Even IDs must be list first
+    //
+    for (Index = 0; Index < MAX_CORE * MAX_THREAD; Index += 2) {
+      SRAAcpiTable->Apic[ThreadIndex].ApicId = (UINT8)ApicTablePtr[Index] + (socket << mNumOfBitShift);
+      SRAAcpiTable->Apic[ThreadIndex].ProximityDomain7To0 = socket; //as ProxDomain are all 0, or we can come up some algorithm if there is any dependency
+      if ((UINT8)ApicTablePtr[Index] != 0xff) {
+        SRAAcpiTable->Apic[ThreadIndex].Flags = EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED;
+      }
+      ThreadIndex++;
+    }  //end of for coreThreadIndex
+  } //end for socket
+
+  for (socket = 0; socket < MAX_SOCKET; socket++) {
+    //
+    // for odd APICID and must be after all even APICIDs
+    //
+    ApicTablePtr = (UINT8*)mApicIdMap[socket];
+    for (Index = 1; Index < MAX_CORE * MAX_THREAD; Index += 2) {
+      SRAAcpiTable->Apic[ThreadIndex].ApicId = (UINT8)ApicTablePtr[Index] + (socket << mNumOfBitShift);
+      SRAAcpiTable->Apic[ThreadIndex].ProximityDomain7To0 = socket; //as ProxDomain are all 0, or we can come up some algorithm if there is any dependency
+      if ((UINT8)ApicTablePtr[Index] != 0xff) {
+        SRAAcpiTable->Apic[ThreadIndex].Flags = EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED;
+      }
+      ThreadIndex++;
+    }
+  }  //end of for coreThreadIndex
+  ASSERT (ThreadIndex == MAX_CPU_NUM);
+  return EFI_SUCCESS;
+}
+
+UINT32
+ProximityDomainOf (
+  UINT8   SocketId,
+  UINT16  MemType,
+  UINT8   MaxEnabledImc,
+  UINT8   SncEnabled,
+  UINT8   SncNumOfCluster,
+  UINT8   ImcInterBitmap,
+  UINT8   MemMode,
+  UINT32  LastDomainId
+  )
+{
+  UINT32  DomainId = (UINT16)~0;
+  INTN    FirstImc;
+  UINT8   ImcPerCluster;
+  UINT8   NumSockets = mIioUds->IioUdsPtr->SystemStatus.numCpus;
+  UINT8   SocketLogicalId;
+
+  EFI_STATUS                      Status = EFI_SUCCESS;
+  DYNAMIC_SI_LIBARY_PROTOCOL2     *DynamicSiLibraryProtocol2 = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  if (SncEnabled == 0) {
+    SncNumOfCluster = 1;
+  }
+
+  if (!DynamicSiLibraryProtocol2->IsMemTypeVolatile (MemType)) {
+    //
+    // Persistent memory nodes and FPGA nodes are just pending behinds volatile memories
+    //
+    DomainId = LastDomainId + 1;
+  } else {
+    SocketLogicalId = GetSocketLogicalId (SocketId);
+    //
+    // Process volatile memory nodes
+    //
+    if (SncEnabled == 0) {
+      DomainId = SocketLogicalId;
+    } else {
+      //
+      // Find the cluster ID using ImcInterBitmap
+      //
+      ImcPerCluster = MAX_IMC / SncNumOfCluster;
+      FirstImc = LowBitSet32 (ImcInterBitmap);
+      if (FirstImc == -1) {
+        FirstImc = 0;
+      }
+      if (MaxEnabledImc <= SncNumOfCluster) {
+        DomainId = (SocketLogicalId * SncNumOfCluster) + (UINT32) (FirstImc / ImcPerCluster);
+      } else {
+        DomainId = (SocketLogicalId * SncNumOfCluster) + ((UINT32) FirstImc) / ImcPerCluster;
+      }
+    }
+    if (MemMode == VOL_MEM_MODE_MIX_1LM2LM) {
+      //
+      // 2LM nodes follow the completion of iteration of all 1LM nodes
+      //
+      DomainId += (UINT32)((DynamicSiLibraryProtocol2->IsMemType2lm (MemType) ? 1 : 0) * NumSockets * SncNumOfCluster);
+    }
+  }
+
+  DEBUG ((DEBUG_INFO, "SocketId = %d, SncEnabled = %d, SncNumOfCluster = %d, ImcInterBitmap = 0x%x, ",
+           SocketId, SncEnabled, SncNumOfCluster, ImcInterBitmap));
+
+  DEBUG ((DEBUG_INFO, "MemType = %d, MemMode = %d, Physical DomainId = %d\n",
+           MemType, MemMode, DomainId));
+
+  return DomainId;
+}
+
+VOID
+PatchMemorySratEntries (
+  IN OUT STATIC_RESOURCE_AFFINITY_TABLE       *SratTable,
+  UINT8                                       SncEnabled,
+  UINT8                                       SncNumOfCluster,
+  UINT8                                       *LastIndexUsed
+  )
+{
+  UINT8   LegacyNodeId;
+  UINT8   NodeId;
+  UINT8   Index;
+  UINT8   TableIndex = 0;
+  UINT8   Socket;
+  UINT32  LastDomainId = 0;
+  UINT64  MemoryAddress;
+  UINT64  MemorySize;
+  UINT8   Pass;
+  UINT8   PrevIndex;
+  BOOLEAN SkipEntry;
+  UINT8   MaxEnabledImc = 0;
+  UINTN   ImcIndex;
+  UINT8   MemSocketBitmap = 0;
+  UINT8   NoMemSocketBitmap;
+  UINT32  ProximityDomain;
+  UINT8   PhysicalClusters;
+  UINT8   VirtualClusters;
+
+  EFI_STATUS                  Status = EFI_SUCCESS;
+  DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return;
+  }
+
+  LegacyNodeId = 0xFF;
+  DEBUG ((DEBUG_INFO, "\nSRAT: Updating SRAT memory information!\n"));
+  DEBUG ((DEBUG_INFO, "Idx  Base              Length           Proximity Flags\n"));
+
+  if (mSystemMemoryMap->VirtualNumaEnable) {
+    PhysicalClusters = SncNumOfCluster / mSystemMemoryMap->VirtualNumOfCluster;
+    VirtualClusters = mSystemMemoryMap->VirtualNumOfCluster;
+  } else {
+    PhysicalClusters = SncNumOfCluster;
+    VirtualClusters = 1;
+  }
+
+  //
+  // Looping the System Memory Map elements twice
+  // Fist loop creates domains for all volatile regions based on socket
+  // The second loop creates domains for all persistent memory ranges
+  //
+  for (Pass = 1; Pass < 3; Pass++ ) {
+    TableIndex = 0;
+    for (Index = 0; Index < mSystemMemoryMap->numberEntries; Index++ ) {
+      SkipEntry = FALSE;
+      NodeId = mSystemMemoryMap->Element[Index].NodeId;
+      ASSERT (NodeId < MC_MAX_NODE);
+
+      if (TableIndex >= MEMORY_AFFINITY_STRUCTURE_COUNT) {
+        ASSERT (0);
+        break;
+      }
+
+      //
+      // Skip any memory region marked reserved
+      //
+      if (DynamicSiLibraryProtocol2->IsMemTypeReserved (mSystemMemoryMap->Element[Index].Type)) {
+        continue;
+      }
+
+      //
+      // As the HOB has base addr in 64 MB chunks
+      //
+      MemoryAddress = ((UINT64)mSystemMemoryMap->Element[Index].BaseAddress << MEM_ADDR_SHFT_VAL);
+
+      //
+      // Skip duplicate entries if applicable
+      //
+      if (TableIndex) {
+        for (PrevIndex = 0; PrevIndex < TableIndex; PrevIndex++) {
+          if (MemoryAddress == ((UINT64)SratTable->Memory[PrevIndex].AddressBaseHigh << 32) + SratTable->Memory[PrevIndex].AddressBaseLow) {
+            SkipEntry = TRUE;
+            break;
+          }
+        }
+      }
+      if (SkipEntry) {
+        continue;
+      }
+
+      //
+      // Update bitmap for sockets with memory populated
+      //
+      if (DynamicSiLibraryProtocol2->IsMemTypeVolatile (mSystemMemoryMap->Element[Index].Type)) {
+        MemSocketBitmap |= BIT0 << mSystemMemoryMap->Element[Index].SocketId;
+      }
+
+      SratTable->Memory[TableIndex].AddressBaseLow = (UINT32)(MemoryAddress & 0xFFFFFFFF);
+      SratTable->Memory[TableIndex].AddressBaseHigh  = (UINT32)((UINTN)MemoryAddress >> 32);
+
+      //
+      // As the HOB has Length in 64 MB chunks
+      //
+      MemorySize  = ((UINT64)mSystemMemoryMap->Element[Index].ElementSize << MEM_ADDR_SHFT_VAL);
+      SratTable->Memory[TableIndex].LengthLow = (UINT32)(MemorySize & 0xFFFFFFFF);
+      SratTable->Memory[TableIndex].LengthHigh = (UINT32)((UINTN)MemorySize >> 32);
+
+      if ((Pass == 2) || DynamicSiLibraryProtocol2->IsMemTypeVolatile (mSystemMemoryMap->Element[Index].Type)) {
+
+        //
+        // Get max enabled IMC for this socket
+        //
+        for (ImcIndex = 0, MaxEnabledImc = 0; ImcIndex < MAX_IMC; ImcIndex++) {
+          if (mSystemMemoryMap->Socket[mSystemMemoryMap->Element[Index].SocketId].imcEnabled[ImcIndex] != 0) {
+            MaxEnabledImc ++;
+          }
+        }
+
+        ProximityDomain = ProximityDomainOf (
+                           mSystemMemoryMap->Element[Index].SocketId,
+                           mSystemMemoryMap->Element[Index].Type,
+                           MaxEnabledImc,
+                           SncEnabled,
+                           PhysicalClusters,
+                           mSystemMemoryMap->Element[Index].ImcInterBitmap,
+                           mSystemMemoryMap->volMemMode,
+                           LastDomainId
+                           );
+        SratTable->Memory[TableIndex].ProximityDomain = (ProximityDomain * VirtualClusters) + (Index % VirtualClusters);
+        if (LastDomainId < SratTable->Memory[TableIndex].ProximityDomain) {
+          LastDomainId = SratTable->Memory[TableIndex].ProximityDomain;
+        }
+        if ((MemoryAddress == 0) && (MemorySize > 0)) {
+          LegacyNodeId = NodeId;
+        }
+
+        //
+        // Enable the Memory structure
+        //
+        if ((LegacyNodeId == NodeId) || (!mSocketMemoryConfiguration.SratMemoryHotPlug) ) {
+          SratTable->Memory[TableIndex].Flags = EFI_ACPI_6_2_MEMORY_ENABLED;
+        } else {
+          SratTable->Memory[TableIndex].Flags = EFI_ACPI_6_2_MEMORY_ENABLED | EFI_ACPI_6_2_MEMORY_HOT_PLUGGABLE;
+        }
+        if (!DynamicSiLibraryProtocol2->IsMemTypeVolatile (mSystemMemoryMap->Element[Index].Type) &&
+            !DynamicSiLibraryProtocol2->IsMemTypeFpga (mSystemMemoryMap->Element[Index].Type)) {
+          SratTable->Memory[TableIndex].Flags |= EFI_ACPI_6_2_MEMORY_NONVOLATILE;
+        }
+
+        if (Pass == 2) {
+          DEBUG ((DEBUG_INFO, "%3d  %08x%08x, %08x%08x %2x         %x\n",
+                 TableIndex,
+                 SratTable->Memory[TableIndex].AddressBaseHigh,
+                 SratTable->Memory[TableIndex].AddressBaseLow,
+                 SratTable->Memory[TableIndex].LengthHigh,
+                 SratTable->Memory[TableIndex].LengthLow,
+                 SratTable->Memory[TableIndex].ProximityDomain,
+                 SratTable->Memory[TableIndex].Flags));
+        }
+      }
+      TableIndex++;
+    }
+    //
+    // Update LastDomainId for enabled sockets with no memory
+    //
+    NoMemSocketBitmap = mCpuCsrAccessVarPtr->socketPresentBitMap & ~MemSocketBitmap;
+    if (Pass == 1) {
+      for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+        if ((BIT0 << Socket) & NoMemSocketBitmap) {
+          LastDomainId += SncNumOfCluster;
+        }
+      }
+    }
+  }
+
+  *LastIndexUsed = TableIndex;
+}
+
+EFI_STATUS
+PatchSratTable (
+  IN OUT STATIC_RESOURCE_AFFINITY_TABLE  *SratTable
+  )
+{
+  UINT8                                     Index;
+  UINT8                                     NewIndex;
+  UINT16                                    ThreadIndex;   // Support more than 256 threads (8S case)
+  UINT8                                     NodeId;
+  UINTN                                     HighTopMemory;
+  UINTN                                     HotPlugBase;
+  UINTN                                     HotPlugLen;
+  UINT8                                     SncEnabled;
+  UINT8                                     SncNumOfCluster;
+
+  SncEnabled      = mIioUds->IioUdsPtr->SystemStatus.OutSncEn;
+  SncNumOfCluster = mIioUds->IioUdsPtr->SystemStatus.OutNumOfCluster;
+
+  if (mSystemMemoryMap != NULL) {
+    if (mSystemMemoryMap->VirtualNumaEnable) {
+     if (SncEnabled) {
+      SncNumOfCluster = SncNumOfCluster * mSystemMemoryMap->VirtualNumOfCluster;
+     } else {
+       //
+       // If Virtual NUMA enabled without SNC, use the number of Virtual NUMA clusters.
+       // Do not multiply by "OutNumOfCluster" if the system is in a UMA Based Clustering mode (e.g. Hemisphere).
+       //
+       SncNumOfCluster = mSystemMemoryMap->VirtualNumOfCluster;
+       SncEnabled = 1;
+     }
+    }
+  }
+
+  if (SncNumOfCluster == 0) {
+    SncNumOfCluster = 1;
+  }
+
+  CollectThreadIdMsrData (SncEnabled, SncNumOfCluster);
+
+  if (mSocketMemoryConfiguration.SratCpuHotPlug) {
+    PatchSratAllApicIds (SratTable);
+  } else {
+    DEBUG (( DEBUG_INFO, "-------- SRAT TABLE ---------- %x\n",  PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE_COUNT));
+
+    for (ThreadIndex = 0; ThreadIndex < PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE_COUNT; ThreadIndex++) {
+      if (ThreadIndex < mNumberOfCPUs) {
+
+        //
+        // Use mCpuThreadIdMsrTable.ApicId by sorting SRAT sequentially to fix proximity domain grouping of threads in OSes
+        //
+        if (mX2ApicEnabled) {
+          SratTable->x2Apic[ThreadIndex].ProximityDomain = GetProximityDomainForSNC (mCpuThreadIdMsrTable[ThreadIndex].ApicId);
+          SratTable->x2Apic[ThreadIndex].X2ApicId = mCpuThreadIdMsrTable[ThreadIndex].ApicId;
+          SratTable->x2Apic[ThreadIndex].Flags = EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED;
+        } else {
+          //
+          // If SNC is enabled and 2 clusters, there is 1 extra Proximity Domain per socket
+          // SNC cannot exist unless all HA's have memory
+          //
+          SratTable->Apic[ThreadIndex].ProximityDomain7To0 = (UINT8)GetProximityDomainForSNC (mCpuThreadIdMsrTable[ThreadIndex].ApicId);
+          SratTable->Apic[ThreadIndex].ApicId = (UINT8)mCpuThreadIdMsrTable[ThreadIndex].ApicId;
+          SratTable->Apic[ThreadIndex].Flags = EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED;
+        }
+      } else {
+        if (mX2ApicEnabled) {
+          SratTable->x2Apic[ThreadIndex].X2ApicId = (UINT32)-1;
+        } else {
+          SratTable->Apic[ThreadIndex].ApicId = 0xFF;
+        }
+      }
+      if (mX2ApicEnabled) {
+          DEBUG (( DEBUG_INFO, "\nSRAT: CpuThreadIndex\t%x, ApicId\t%x,  Flags\t%x!\n",
+                ThreadIndex, SratTable->x2Apic[ThreadIndex].X2ApicId, SratTable->x2Apic[ThreadIndex].Flags));
+      } else {
+          DEBUG (( DEBUG_INFO, "\nSRAT: CpuThreadIndex\t%x, ApicId\t%x,  Flags\t%x, ProximityDomain\t%x!\n",
+                ThreadIndex, SratTable->Apic[ThreadIndex].ApicId, SratTable->Apic[ThreadIndex].Flags,
+                SratTable->Apic[ThreadIndex].ProximityDomain7To0));
+      }
+    }
+  }
+
+  if (mSystemMemoryMap != NULL) {
+
+    PatchMemorySratEntries (SratTable, SncEnabled, SncNumOfCluster, &Index);
+
+    HotPlugBase = 0x100;
+    if (mSocketMemoryConfiguration.MemoryHotPlugBase == 0) { // Auto
+      //
+      // Read the actual TOHM and set it as the hot memory base
+      //
+      HighTopMemory  = (UINT64)mIioUds->IioUdsPtr->SystemStatus.tohmLimit << 26;
+      HotPlugBase = (HighTopMemory >> 32);
+      if ((UINT32)HighTopMemory > 0) {
+        HotPlugBase++;
+      }
+    } else if (mSocketMemoryConfiguration.MemoryHotPlugBase) { // Number
+      HotPlugBase = mSocketMemoryConfiguration.MemoryHotPlugBase * 0x80;
+    }
+    HotPlugLen = (mSocketMemoryConfiguration.MemoryHotPlugLen + 1) * 0x10;
+
+    if (mSocketMemoryConfiguration.SratMemoryHotPlug) {
+      DEBUG (( DEBUG_INFO, "SRAT: Updating SRAT hotplug memory information!\n" ));
+      for (NodeId = 0; NodeId < MC_MAX_NODE; NodeId++) {
+        NewIndex = Index + NodeId;
+        if (NewIndex >= MEMORY_AFFINITY_STRUCTURE_COUNT) {
+          ASSERT (0);
+          break;
+        }
+        //
+        // As the HOB has base addr in 1 GB chunks
+        //
+        SratTable->Memory[NewIndex].ProximityDomain = (NodeId >> 1);
+        SratTable->Memory[NewIndex].AddressBaseLow  = 0;
+        SratTable->Memory[NewIndex].AddressBaseHigh = (UINT32)(HotPlugBase +  NodeId * HotPlugLen);
+        SratTable->Memory[NewIndex].LengthLow  = 0;
+        SratTable->Memory[NewIndex].LengthHigh = (UINT32)HotPlugLen;
+        SratTable->Memory[NewIndex].Flags = EFI_ACPI_6_2_MEMORY_ENABLED | EFI_ACPI_6_2_MEMORY_HOT_PLUGGABLE;
+
+        DEBUG ((DEBUG_INFO, "%3d  %08x%08x  %08x%08x %x %x\n", NewIndex,
+                SratTable->Memory[Index].AddressBaseHigh,
+                SratTable->Memory[Index].AddressBaseLow,
+                SratTable->Memory[Index].LengthHigh,
+                SratTable->Memory[Index].LengthLow,
+                SratTable->Memory[Index].ProximityDomain,
+                SratTable->Memory[NewIndex].Flags));
+      }
+    }
+    //
+    // Copy SRAT memory affinity data to ACPI platform protocol
+    //
+    DEBUG ((DEBUG_INFO, "ACPI Platform Protocol - Memory Affinity Data updated\n"));
+    ZeroMem (&mAcpiPlatformMemAffData, sizeof (mAcpiPlatformMemAffData));
+    CopyMem (&mAcpiPlatformMemAffData.AcpiMemAffData[0], &SratTable->Memory[0], sizeof (mAcpiPlatformMemAffData.AcpiMemAffData));
+    mAcpiPlatformMemAffData.AcpiMemAffDataValid = TRUE;
+  }
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Routine Description:
+    Collect ThreadIdMsr Value for all the AP's and sorts it by the ThreadIdMsr Value.
+    The Sorted Table, for every socket the first half of the threads will be Mapped to 1st HA
+    The second half f threads in every socket will mapped to 2nd HA.
+
+  Arguments:
+    NONE
+
+  Returns:
+    NONE
+**/
+VOID
+CollectThreadIdMsrData (
+  IN UINT8        SncEnabled,
+  IN UINT8        SncNumOfCluster
+  )
+{
+  UINT32                      SocketIndex;
+  UINT32                      ThreadIndex;
+  UINTN                       NumOfChaPerCluster;
+  BOOLEAN                     CollocatedChaIdPresent;
+  UINT32                      NumberOfThreads;
+  UINT8                       SocketLogicalId;
+
+  NumOfChaPerCluster = 0;
+  CollocatedChaIdPresent = FALSE;
+  AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &NumberOfThreads, NULL, NULL);
+
+  //
+  // Get total number of CHAs per socket
+  //
+  for(SocketIndex = 0; SocketIndex < MAX_SOCKET; SocketIndex++) {
+    mPackageChaTotal[SocketIndex] = mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[SocketIndex].TotCha;
+  }
+
+  //
+  // Determine whether collocated CHA ID is encoded in upper 32 bits of MSR 0x53 LOGICAL_THREAD_ID
+  //
+  if (SncEnabled) {
+    for(ThreadIndex = 0; ThreadIndex < (MAX_CORE * MAX_THREAD); ThreadIndex++) {
+      if (mCpuThreadIdMsrTable[ThreadIndex].CollocatedChaId != 0) {
+        if (mCpuThreadIdMsrTable[ThreadIndex].CollocatedChaId != 0xFF) {
+          CollocatedChaIdPresent = TRUE;
+        }
+        break;
+      }
+    }
+    if (!CollocatedChaIdPresent) {
+      DEBUG ((DEBUG_WARN, "ERROR: Collocated CHA ID is not found! Correct SNC Proximity Domain programming not guaranteed.\n"));
+    }
+  }
+
+  //
+  // Set SNC Proximity Domain variables for each thread
+  //
+  for(ThreadIndex = 0; ThreadIndex < MAX_CPU_NUM; ThreadIndex++) {
+    if (mCpuThreadIdMsrTable[ThreadIndex].ThreadIdValue == 0xff) {
+      continue;
+    }
+
+    //
+    // We divide cores in group by number of clusters.
+    // CHA number is used instead of active threads to account for when cores or
+    // threads are disabled.
+    //
+    SocketIndex = mCpuConfigLibConfigContextBuffer->CollectedDataBuffer[ThreadIndex].ProcessorLocation.Package;
+    SocketLogicalId = GetSocketLogicalId ((UINT8) SocketIndex);
+    if (!SncEnabled) {
+      mCpuThreadIdMsrTable[ThreadIndex].SNCProximityDomain = SocketLogicalId;
+    } else {
+      NumOfChaPerCluster = mPackageChaTotal[SocketIndex]/SncNumOfCluster;
+      if (CollocatedChaIdPresent) {
+        mCpuThreadIdMsrTable[ThreadIndex].SNCProximityDomain = (UINT32)((SocketLogicalId * SncNumOfCluster) + (mCpuThreadIdMsrTable[ThreadIndex].CollocatedChaId / (NumOfChaPerCluster)));
+      } else {
+        mCpuThreadIdMsrTable[ThreadIndex].SNCProximityDomain = (UINT32)((SocketLogicalId * SncNumOfCluster) + (mCpuThreadIdMsrTable[ThreadIndex].ThreadIdValue / (NumOfChaPerCluster*NumberOfThreads)));
+      }
+      DEBUG ((DEBUG_INFO, "ThreadIndex=%x, SncNumOfCluster=%x, NumOfChaPerCluster=%x, SNCProximityDomain=%x\n", ThreadIndex, SncNumOfCluster, NumOfChaPerCluster, mCpuThreadIdMsrTable[ThreadIndex].SNCProximityDomain));
+      DEBUG ((DEBUG_INFO, "ThreadIdValue=%x\n", mCpuThreadIdMsrTable[ThreadIndex].ThreadIdValue));
+    }
+  }
+}
+
+/**
+  Return the Domain Flag value of the specific APICID
+  Proximity Domain Flag
+    0 Denotes upper half of the sorted thread needs to be mapped to 1st HA.
+    1 Denotes lower half and mapped to 2nd HA
+
+  @retval      Proximity Domain Value for the thread within a Socket.
+**/
+UINT32
+GetProximityDomainForSNC (
+  IN  UINT32 ApicId
+  )
+{
+  UINT32 ThreadIndex     = 0;
+  static UINT32 SncIndex = 0;
+
+  //
+  // The ApicIds are in order. Saving the index will reduce loop iterations
+  //
+  for (ThreadIndex = SncIndex; ThreadIndex < MAX_CPU_NUM; ThreadIndex++) {
+    if (mCpuThreadIdMsrTable[ThreadIndex].ApicId == ApicId){
+      SncIndex = ThreadIndex + 1;
+      return mCpuThreadIdMsrTable[ThreadIndex].SNCProximityDomain;
+    } else if (mCpuThreadIdMsrTable[ThreadIndex].ApicId == (UINT32) -1) {
+      //
+      // We have reached the end of the populated threads
+      //
+      break;
+    }
+  }
+
+  //
+  // Start again from the beginning if we made it to the end of the array
+  //
+  for (ThreadIndex = 0; ThreadIndex < MAX_CPU_NUM; ThreadIndex++) {
+    if (mCpuThreadIdMsrTable[ThreadIndex].ApicId == ApicId){
+      SncIndex = ThreadIndex + 1;
+      return mCpuThreadIdMsrTable[ThreadIndex].SNCProximityDomain;
+    }
+  }
+
+  DEBUG ((DEBUG_ERROR, "APICID not found in CpuThreadIdMsrValueTable\n"));
+  ASSERT (FALSE);
+  ThreadIndex--;
+  return mCpuThreadIdMsrTable[ThreadIndex].SNCProximityDomain;
+}
+
+/**
+  Function retrieves selected data of ACPI SRAT Memory Affinity Structures
+  (please note that data will not be available until SRAT table installation)
+
+  @param[out] *MemAffData         ACPI Memory Affinity Data
+  @param[out] *MemAffDataLength   ACPI Memory Affinity Data Length
+
+  @retval EFI_SUCCESS             ACPI Memory Affinity Data retrieved successfully
+  @retval EFI_NOT_FOUND           ACPI Memory Affinity Data not found (SRAT ACPI table was not published)
+  @retval EFI_INVALID_PARAMETER   One or more of input arguments is NULL
+**/
+EFI_STATUS
+GetAcpiMemoryAffinityData (
+  OUT ACPI_MEMORY_AFFINITY_DATA **MemAffData,
+  OUT UINTN                     *MemAffDataLength
+  )
+{
+  if (MemAffData == NULL || MemAffDataLength == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (!mAcpiPlatformMemAffData.AcpiMemAffDataValid) {
+    return EFI_NOT_FOUND;
+  }
+
+  *MemAffData = mAcpiPlatformMemAffData.AcpiMemAffData;
+  *MemAffDataLength = (UINT8)MEMORY_AFFINITY_STRUCTURE_COUNT;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Function initialize and install ACPI Platform Protocol
+
+  @param None
+
+  @retval EFI_SUCCESS Operation completed successfully
+**/
+EFI_STATUS
+InstallAcpiPlatformProtocol (
+  VOID
+  )
+{
+  EFI_HANDLE Handle = NULL;
+
+  ZeroMem (&mAcpiPlatformProtocol, sizeof(mAcpiPlatformProtocol));
+  mAcpiPlatformProtocol.GetAcpiMemoryAffinityData = GetAcpiMemoryAffinityData;
+
+  return gBS->InstallProtocolInterface (&Handle, &gAcpiPlatformProtocolGuid, EFI_NATIVE_INTERFACE, &mAcpiPlatformProtocol);
+}
+
+VOID
+PrintSratTable (
+  IN EFI_ACPI_DESCRIPTION_HEADER *Header
+  )
+{
+  EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER          *Table;
+  EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE  *SubType;
+  UINTN                                                       TotalLength;
+  UINT8                                                       *TempPtr;
+  EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE  *ApicType;
+  EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE                      *MemType;
+  EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE      *x2ApicType;
+  UINTN                                                       TempLength;
+
+  Table = (EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER *) Header;
+  if (Table->Header.Signature != EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE) {
+    DEBUG ((DEBUG_ERROR, "[SRAT] Not SRAT table, skip!\n"));
+    return;
+  }
+
+  TotalLength = Table->Header.Length;
+
+  DEBUG ((DEBUG_INFO, "----------------------------[SRAT Table] --------------------\n"));
+  DEBUG ((DEBUG_INFO, "----Header-----\n"));
+  DEBUG ((DEBUG_INFO, "Length          :  %d\n", Table->Header.Length));
+  DEBUG ((DEBUG_INFO, "Revision        :  %d\n", Table->Header.Revision));
+  DEBUG ((DEBUG_INFO, "Checksum        :  %2X\n", Table->Header.Checksum));
+  DEBUG ((DEBUG_INFO, "OemTableId      :  %X\n", Table->Header.OemTableId));
+  DEBUG ((DEBUG_INFO, "OemRevision     :  %d\n", Table->Header.OemRevision));
+  DEBUG ((DEBUG_INFO, "CreatorId       :  %X\n", Table->Header.CreatorId));
+  DEBUG ((DEBUG_INFO, "CreatorRevision :  %X\n", Table->Header.CreatorRevision));
+  DEBUG ((DEBUG_INFO, "\n"));
+
+  TempPtr = (UINT8 *)Table;
+  TempPtr += sizeof(EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER);
+  TempLength = ((EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE *) TempPtr)->Length;
+  while (TempPtr < ((UINT8 *)Table + TotalLength)){
+    SubType = (EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE *) TempPtr;
+    if (SubType->Type == EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY) {
+      ApicType = SubType;
+      DEBUG ((DEBUG_INFO, "APIC Type            :  %d\n", ApicType->Type));
+      DEBUG ((DEBUG_INFO, "Length               :  %d\n", ApicType->Length));
+      DEBUG ((DEBUG_INFO, "ProximityDomain7To0  :  %d\n", ApicType->ProximityDomain7To0));
+      DEBUG ((DEBUG_INFO, "ApicId               :  %X\n", ApicType->ApicId));
+      DEBUG ((DEBUG_INFO, "Flags                :  %X\n", ApicType->Flags));
+      DEBUG ((DEBUG_INFO, "LocalSapicEid        :  %d\n", ApicType->LocalSapicEid));
+      DEBUG ((DEBUG_INFO, "ProximityDomain31To8 :  %d\n", (*(UINT32 *)ApicType->ProximityDomain31To8) & 0xFFFFFF));
+      DEBUG ((DEBUG_INFO, "ClockDomain          :  %d\n", ApicType->ClockDomain));
+
+    } else if (SubType->Type == EFI_ACPI_6_2_MEMORY_AFFINITY) {
+      MemType = (EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE *)SubType;
+      DEBUG ((DEBUG_INFO, "Mem Type        :  %d\n", MemType->Type));
+      DEBUG ((DEBUG_INFO, "Length          :  %d\n", MemType->Length));
+      DEBUG ((DEBUG_INFO, "ProximityDomain :  %d\n", MemType->ProximityDomain));
+      DEBUG ((DEBUG_INFO, "AddressBaseLow  :  %X\n", MemType->AddressBaseLow));
+      DEBUG ((DEBUG_INFO, "AddressBaseHigh :  %X\n", MemType->AddressBaseHigh));
+      DEBUG ((DEBUG_INFO, "LengthLow       :  %X\n", MemType->LengthLow));
+      DEBUG ((DEBUG_INFO, "LengthHigh      :  %X\n", MemType->LengthHigh));
+      DEBUG ((DEBUG_INFO, "Flags           :  %X\n", MemType->Flags));
+
+    } else if (SubType->Type == EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY) {
+      x2ApicType = (EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE *) SubType;
+      DEBUG ((DEBUG_INFO, "x2APIC Type     :  %d\n", x2ApicType->Type));
+      DEBUG ((DEBUG_INFO, "Length          :  %d\n", x2ApicType->Length));
+      DEBUG ((DEBUG_INFO, "ProximityDomain :  %d\n", x2ApicType->ProximityDomain));
+      DEBUG ((DEBUG_INFO, "X2ApicId        :  %X\n", x2ApicType->X2ApicId));
+      DEBUG ((DEBUG_INFO, "Flags           :  %X\n", x2ApicType->Flags));
+      DEBUG ((DEBUG_INFO, "ClockDomain     :  %d\n", x2ApicType->ClockDomain));
+
+    } else {
+      DEBUG ((DEBUG_INFO, "Unknown Type : %d\n", SubType->Type));
+      DEBUG ((DEBUG_INFO, "Length : %d\n", SubType->Length));
+    }
+    if (SubType->Length < 10) {
+      DEBUG ((DEBUG_ERROR, "Error in Length %d, try previous length.\n", SubType->Length));
+      TempPtr += TempLength;
+    } else {
+      TempPtr += SubType->Length;
+      TempLength = SubType->Length;
+    }
+    DEBUG ((DEBUG_INFO, "\n"));
+  }
+}
+
+/**
+  Build from scratch and install the SRAT.
+
+  @retval EFI_SUCCESS           The SRAT was installed successfully.
+  @retval EFI_OUT_OF_RESOURCES  Could not allocate required structures.
+**/
+EFI_STATUS
+InstallSratTable (
+  VOID
+  )
+{
+  EFI_STATUS                                          Status;
+  UINTN                                               Index;
+  UINTN                                               TableHandle;
+  UINTN                                               TableSize;
+  STATIC_RESOURCE_AFFINITY_TABLE                      *SratTable;
+
+  Status = EFI_SUCCESS;
+  TableHandle = 0;
+
+  if (mSocketMemoryConfiguration.Srat == 0)  {
+    return EFI_SUCCESS;
+  }
+
+  if  (mSystemMemoryMap == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  SratTable = (STATIC_RESOURCE_AFFINITY_TABLE *) AllocateZeroPool (sizeof(STATIC_RESOURCE_AFFINITY_TABLE));
+  if (SratTable == NULL) {
+    DEBUG ((DEBUG_ERROR, "InstallSratTable: allocate SRAT table failed \n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  TableSize = sizeof (EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER) +
+              sizeof (EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE) * PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE_COUNT +
+              sizeof (EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE) * MEMORY_AFFINITY_STRUCTURE_COUNT +
+              sizeof (EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE) * X2APIC_AFFINITY_STRUCTURE_COUNT ;
+
+  SratTable->SratHeader = (EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER *) AllocateZeroPool (TableSize);
+  if (SratTable->SratHeader == NULL) {
+    DEBUG ((DEBUG_ERROR, "InstallSratTable: Create SratHeader has failed \n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  SratTable->Apic = (EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE *) (UINTN)((UINTN)SratTable->SratHeader +
+                      (UINTN)sizeof(EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER));
+
+  SratTable->Memory = (EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE *) (UINTN)((UINTN)SratTable->Apic +
+                      (UINTN)sizeof(EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE) * PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE_COUNT);
+
+  SratTable->x2Apic = (EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE *) (UINTN)((UINTN)SratTable->Memory +
+                      (UINTN)sizeof(EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE)* MEMORY_AFFINITY_STRUCTURE_COUNT);
+
+
+  SratTable->SratHeader->Header.Signature = EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE;
+  SratTable->SratHeader->Header.Length = (UINT32) TableSize;
+  SratTable->SratHeader->Header.Revision = EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION;
+  CopyMem (SratTable->SratHeader->Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (SratTable->SratHeader->Header.OemId));
+  SratTable->SratHeader->Header.OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+  SratTable->SratHeader->Header.OemRevision = EFI_ACPI_OEM_SRAT_REVISION;
+  SratTable->SratHeader->Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+  SratTable->SratHeader->Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+
+  SratTable->SratHeader->Reserved1 = EFI_ACPI_SRAT_RESERVED_FOR_BACKWARD_COMPATIBILITY;
+  SratTable->SratHeader->Reserved2 = EFI_ACPI_RESERVED_QWORD;
+
+  for (Index = 0; Index < PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE_COUNT; Index++) {
+    SratTable->Apic[Index].Type = EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY;
+    SratTable->Apic[Index].Length = sizeof(EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE);
+    SratTable->Apic[Index].ApicId = 0xFF;
+  }
+
+  for (Index = 0; Index < MEMORY_AFFINITY_STRUCTURE_COUNT; Index++) {
+    SratTable->Memory[Index].Type = EFI_ACPI_6_2_MEMORY_AFFINITY;
+    SratTable->Memory[Index].Length = sizeof(EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE);
+  }
+
+  for (Index = 0; Index < X2APIC_AFFINITY_STRUCTURE_COUNT; Index++) {
+    SratTable->x2Apic[Index].Type = EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY;
+    SratTable->x2Apic[Index].Length = sizeof(EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE);
+    SratTable->x2Apic[Index].X2ApicId = 0xFFFFFFFF;
+  }
+
+  PatchSratTable (SratTable);
+  PrintSratTable (&SratTable->SratHeader->Header);
+
+  //
+  // Publish SRAT Structure to ACPI
+  //
+  Status = mAcpiTable->InstallAcpiTable (
+                          mAcpiTable,
+                          SratTable->SratHeader,
+                          SratTable->SratHeader->Header.Length,
+                          &TableHandle
+                          );
+
+
+  FreePool (SratTable->SratHeader);
+  FreePool (SratTable);
+
+  InstallAcpiPlatformProtocol ();
+
+  return Status;
+}

+ 1004 - 0
Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSsdt.c

@@ -0,0 +1,1004 @@
+/** @file
+  ACPI Platform Driver Hooks
+
+  @copyright
+  Copyright 1996 - 2020 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include "AcpiPlatformLibLocal.h"
+#include <Protocol/DynamicSiLibraryProtocol2.h>
+
+extern BIOS_ACPI_PARAM             *mAcpiParameter;
+extern EFI_IIO_UDS_PROTOCOL        *mIioUds;
+
+extern SOCKET_MEMORY_CONFIGURATION mSocketMemoryConfiguration;
+extern SOCKET_POWERMANAGEMENT_CONFIGURATION mSocketPowermanagementConfiguration;
+
+extern BOOLEAN      mCpuOrderSorted;
+extern UINT32       mApicIdMap[MAX_SOCKET][MAX_CORE * MAX_THREAD];
+extern UINT32       mNumOfBitShift;
+
+extern UINT32       mEnabledProcessor[MAX_SOCKET];
+
+extern EFI_CPU_CSR_ACCESS_PROTOCOL *mCpuCsrAccess;
+UINT32 mCpuPCPSInfo[MAX_SOCKET];
+UINT32 mNcpuValue[MAX_SOCKET];
+
+extern CPU_ID_ORDER_MAP             mCpuApicIdOrderTable[];
+extern UINT8                        mPStateEnable;
+
+#ifndef MSR_MISC_ENABLES
+#define MSR_MISC_ENABLES         0x01A0
+#endif
+
+/**
+  This function detects PCPS Info
+
+  mCpuPCPSInfo usage:
+    Bit[15:0]: Enabled processors in current socket
+    Bit[16]: Hyperthreading enable
+    Bit[17]: PCPS disable in system
+
+  @param None
+
+  @retval VOID
+
+**/
+VOID
+DetectPcpsInfo (
+  VOID
+  )
+{
+  UINT8                   Socket;
+  UINT32                  CpuPCPSInfo = 0;
+  UINT32                  SmtDisable = 0;
+  UINT32                  Csr;
+
+  EFI_STATUS                      Status = EFI_SUCCESS;
+  DYNAMIC_SI_LIBARY_PROTOCOL2     *DynamicSiLibraryProtocol2 = NULL;
+
+  Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return;
+  }
+
+  for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+    if (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].Valid) {
+      SmtDisable = DynamicSiLibraryProtocol2->PcuGetDesiredCoreSmtDis (Socket);
+
+      Csr = mCpuCsrAccess->ReadCpuCsr (Socket, 0, 0x04320084);
+
+      if (!SmtDisable && !(Csr & (1 << 12))) {
+        mCpuPCPSInfo[Socket] |= B_PCPS_HT_ENABLE;
+      }
+      CpuPCPSInfo = mCpuPCPSInfo[Socket];
+
+      //
+      // Update NCPU
+      //
+      mNcpuValue[Socket] = mCpuPCPSInfo[Socket] & 0xFF;
+
+      if (((CpuPCPSInfo & B_PCPS_DISABLE) == 0)) {
+        if (CpuPCPSInfo & B_PCPS_HT_ENABLE) {
+          mNcpuValue[Socket] = 2;
+        } else {
+          mNcpuValue[Socket] = 1;
+        }
+      }
+    }
+  }
+
+  for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+    if (mCpuPCPSInfo[Socket] == 0) {
+      mCpuPCPSInfo[Socket] = CpuPCPSInfo;
+      mNcpuValue[Socket] = mNcpuValue[0];
+    }
+  }
+}
+
+/**
+  Find APICID in mCpuApicIdOrderTable
+
+  @param SocketIndex      - In: Acpi thread number
+  @param ThreadIndex      - In: Acpi thread number
+
+  @retval APICID     - If not found, return 0xFFFFFFFF
+**/
+UINT32
+LocateApicIdInfo (
+  IN   UINT32                 SocketIndex,
+  IN   UINT32                 ThreadIndex
+  )
+{
+  if (mApicIdMap[SocketIndex][ThreadIndex] == (UINT32) -1) {
+    return (UINT32) -1;
+  }
+
+  return (mApicIdMap[SocketIndex][ThreadIndex] + (SocketIndex << mNumOfBitShift));
+}
+
+/**
+  Gather the EIST information
+
+  @param ThreadId       - In: Acpi thread number
+  @param CpuMiscData    - In/Out: Pointer to thread's CPU_MISC_DTAT struct
+
+  @retval EFI_SUCCESS   - EIST info retrieved
+**/
+EFI_STATUS
+LocateCpuEistInfo (
+  IN   UINT32                        CpuIndex,
+  OUT  CPU_MISC_DATA                 **CpuMiscData
+  )
+{
+  UINTN                       Index;
+  UINT32                      Socket;
+  UINT32                      ApicId;
+  const UINT32                *ApicMapPtr;
+
+  Socket = CpuIndex / (MAX_CORE * MAX_THREAD);
+  Index  = CpuIndex % (MAX_CORE * MAX_THREAD);
+  ApicMapPtr = mApicIdMap[Socket];
+
+  ApicId = mAcpiParameter->ProcessorApicIdBase[Socket] + ApicMapPtr[Index];
+
+  for (Index = 0; Index < mCpuConfigLibConfigContextBuffer->NumberOfProcessors; ++Index) {
+    if (mCpuConfigLibConfigContextBuffer->CollectedDataBuffer[Index].CpuMiscData.ApicID == ApicId) {
+      *CpuMiscData = &mCpuConfigLibConfigContextBuffer->CollectedDataBuffer[Index].CpuMiscData;
+      break;
+    }
+  }
+
+  if (*CpuMiscData == NULL) {  //use SBSP's data
+    *CpuMiscData = &mCpuConfigLibConfigContextBuffer->CollectedDataBuffer[0].CpuMiscData;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Determine turbo mode status
+
+  @param None
+
+  @retval TRUE if turbo enabled, FALSE if disabled
+**/
+BOOLEAN
+IsTurboModeEnabled (
+  VOID
+  )
+{
+  EFI_CPUID_REGISTER     CpuidRegisters;
+  BOOLEAN                Status;
+  UINT64                 MiscEnable;
+
+  Status = FALSE;
+  AsmCpuid (CPUID_THERMAL_POWER_MANAGEMENT, &CpuidRegisters.RegEax, &CpuidRegisters.RegEbx, &CpuidRegisters.RegEcx, &CpuidRegisters.RegEdx);
+  if (((CPUID_THERMAL_POWER_MANAGEMENT_EAX*)&CpuidRegisters.RegEax)->Bits.TurboBoostTechnology != 0) {
+    //
+    // Turbo mode is supported on this processor (Available)
+    //
+
+    MiscEnable = AsmReadMsr64 (MSR_MISC_ENABLES);
+    if ((RShiftU64 (MiscEnable, 38) & 1) == 0) { // Bit 38 is TurboModeDisable
+      //
+      // Turbo mode is supported on this processor (Available)
+      //
+      Status = TRUE;
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Finds the actual beginning of a CPU SSDT table, skips the If(Zero) { External() ... } opcode
+  auto-generated by the iASL 6.1 compiler
+
+  From iASL/6.1/changes.txt
+  "Completed full support for the ACPI 6.0 External() AML opcode. The
+  compiler emits an external AML opcode for each ASL External statement.
+  This opcode is used by the disassembler to assist with the disassembly of
+  external control methods by specifying the required number of arguments
+  for the method. AML interpreters do not use this opcode. To ensure that
+  interpreters do not even see the opcode, a block of one or more external
+  opcodes is surrounded by an "If(0)" construct. As this feature becomes
+  commonly deployed in BIOS code, the ability of disassemblers to correctly
+  disassemble AML code will be greatly improved."
+
+  The AML code contains external (_SB_SCKxCyyy) opcodes within a If(Zero) statement;
+  we have to ignore this opcodes and start patching from the actual table begin marker, i.e., "TBST"
+
+  @param[in] BeginPtr a pointer to the begin of a SSDT table
+  @param[in] EndPtr   a pointer to the end of a SSDT table
+
+  @retval       beginning of the part of SSDT table past external _SB_ opcodes
+**/
+static inline
+UINT8 *
+SkipExternalSbOpcodes(
+  IN UINT8  *BeginPtr,
+  IN UINT8  *EndPtr,
+  IN UINT32 ExternSbExpected
+  )
+{
+  UINT8  *CurPtr = BeginPtr;
+  UINT32 ExternSbFound = 0;
+
+  ASSERT (BeginPtr < EndPtr);
+
+  DEBUG ((DEBUG_VERBOSE, "SkipExternalSbOpcodes start\n"));
+
+  for (CurPtr = BeginPtr; CurPtr < EndPtr; ++CurPtr) {
+    UINT32 Signature = *(UINT32 *) CurPtr;
+
+    if (SIGNATURE_32 ('_', 'S', 'B', '_') == Signature) {
+      CONST EXTERNAL_OBJECT_DECL *ExternDecl = ACPI_EXTERNAL_OBJECT_DECL_FROM_NAME_STR (CurPtr);
+
+      ASSERT (BeginPtr < (UINT8 *)ExternDecl);
+
+      if ((AML_EXTERNAL_OP == ExternDecl->ExternalOp ) &&
+          (AML_ROOT_CHAR == ExternDecl->RootChar) &&
+          (AML_MULTI_NAME_PREFIX == ExternDecl->MultiNamePrefix) &&
+          (0x3 <= ExternDecl->SegCount)) {
+        ++ExternSbFound;
+      } else {
+        break;
+      }
+    }
+  }
+
+  DEBUG ((DEBUG_ERROR, "ExternSbExpected: %d, ExternSbFound: %d\n"));
+
+  ASSERT ((ExternSbFound % ExternSbExpected) == 0);
+
+  DEBUG ((DEBUG_VERBOSE, "SkipExternalSbOpcodes end\n"));
+
+  return CurPtr;
+}
+
+/**
+  Update the CPU PM SSDT table
+
+  @param[in,out]  TableHeader     The table to be set
+
+  @retval         EFI_SUCCESS     Returns Success
+  @retval         EFI_UNSUPPORTED Table is not supported
+**/
+EFI_STATUS
+PatchCpuPmSsdtTable (
+  IN OUT  EFI_ACPI_COMMON_HEADER      *Table
+  )
+{
+  UINT8                       *CurrPtr;
+  UINT8                       *EndPtr;
+  UINT8                       *SsdtPointer;
+  UINT32                      Signature;
+  UINT32                      CpuFixes;
+  UINT32                      CpuSkt;
+  UINT32                      CpuIndex;
+  UINT32                      ThreadIndex;
+  UINT32                      AdjustSize;
+  ACPI_NAMEPACK_DWORD         *NamePtr;
+  UINT32                      DomnValue;
+  ACPI_NAME_COMMAND           *PsdPackage;
+  PSD_PACKAGE_LAYOUT          *PsdPackageItemPtr;
+  CPU_MISC_DATA               *CpuMiscData;
+
+  DEBUG ((DEBUG_INFO, "Patching SSDT PatchCpuPmSsdtTable\n"));
+
+  //
+  // Loop through the ASL looking for values that we must fix up.
+  //
+  DomnValue = 0;
+  CpuFixes  = 0;
+  CpuSkt    = 0;
+  CpuIndex  = 0;
+  ThreadIndex = 0;
+  CurrPtr = (UINT8 *) Table;
+  EndPtr  = (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length);
+  CpuMiscData = NULL;
+
+  DetectPcpsInfo ();
+
+  //
+  // CurrPtr = beginning of table to search
+  //
+  CurrPtr = SkipExternalSbOpcodes (CurrPtr, EndPtr, (UINT32) MAX_CPU_NUM);
+
+  //
+  // Subtract 11 from EndPtr - this is the size of the largest data item we will search for
+  //  so that we do not try to read past the end of the table
+  //
+  EndPtr -= 11;
+
+  for (SsdtPointer = CurrPtr; SsdtPointer <= EndPtr; ++SsdtPointer) {
+    Signature = *(UINT32 *) SsdtPointer;
+    CpuIndex  = 0;
+    AdjustSize  = 0;
+
+    switch (Signature) {
+
+    //
+    // The AML code contains strings in the form of _SB_SCKxCyyy where x is the socket number
+    // and yyy is the thread number in hexadecimal, this first case parses that string and saves
+    // the socket number into CpuSkt and the thread number into CpuIndex.
+    //
+    case SIGNATURE_32 ('_', 'S', 'B', '_'):
+      //
+      // SKTX
+      //
+      CpuSkt = *(SsdtPointer + 7);
+      if ((CpuSkt < '0') || ((CpuSkt - '0') > MAX_SOCKET)) {
+        CpuSkt = '0';
+      }
+      CpuSkt -= '0';
+
+      if ((*(SsdtPointer + 8) != 'C')) {
+        continue;
+      }
+
+      if ((*(SsdtPointer + 11) > '0') && (*(SsdtPointer + 11) <= '9')) {
+        CpuIndex = (*(SsdtPointer + 11) -'0');
+      } else if ((*(SsdtPointer + 11) >= 'A') && (*(SsdtPointer + 11) <= 'F')) {
+        CpuIndex = (*(SsdtPointer + 11) -'A' + 10);
+      }
+
+      if ((*(SsdtPointer + 10) > '0') && ( *(SsdtPointer + 10) <= '9')) {
+        AdjustSize = (*(SsdtPointer + 10) -'0') * 0x10;
+      } else if ((*(SsdtPointer + 10) >= 'A') && (*(SsdtPointer + 10) <= 'F')) {
+        AdjustSize = (*(SsdtPointer + 10) -'A' + 10) * 0x10;
+      }
+
+      CpuIndex += AdjustSize;
+      AdjustSize  = 0;
+
+      if ((*(SsdtPointer + 9) > '0') && (*(SsdtPointer + 9) <= '9')) {
+        AdjustSize = (*(SsdtPointer + 9) -'0') * 0x100;
+      } else if ((*(SsdtPointer + 9) >= 'A') && (*(SsdtPointer + 9) <= 'F')) {
+        AdjustSize = (*(SsdtPointer + 9) -'A' + 10) * 0x100;
+      }
+
+      CpuIndex += AdjustSize;
+      ThreadIndex  = CpuIndex;
+
+      //
+      // PCPS - Update DOMN
+      //
+      DomnValue = (UINT8) CpuSkt;
+
+      if ((mCpuPCPSInfo[CpuSkt] & B_PCPS_DISABLE) == 0) {
+        DomnValue = LocateApicIdInfo (CpuSkt, ThreadIndex);
+
+        if (mNcpuValue[CpuSkt] == 2) {
+          DomnValue = (DomnValue >> 1);
+        }
+      }
+
+      DEBUG ((
+        DEBUG_INFO,
+        ":ACPI: PatchCpuPmSsdtTable(): CpuSkt: %d ThreadIndex: %d, NcpuValue: %d, DomnValue: %d\n",
+        CpuSkt,
+        ThreadIndex,
+        mNcpuValue[CpuSkt],
+        DomnValue
+        ));
+      ++CpuFixes;
+      CpuMiscData = NULL;
+      LocateCpuEistInfo (0, &CpuMiscData);  // use CPU0 for update NPSS and SPSS
+      break;
+
+    case SIGNATURE_32 ('D', 'O', 'M', 'N'):
+      NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (SsdtPointer);
+      if (NamePtr->StartByte != AML_NAME_OP) {
+        continue;
+      }
+
+      if (NamePtr->Size != AML_NAME_DWORD_SIZE) {
+        continue;
+      }
+
+      NamePtr->Value = DomnValue;
+      break;
+
+    case SIGNATURE_32 ('N', 'C', 'P', 'U'):
+      NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (SsdtPointer);
+      if (NamePtr->StartByte != AML_NAME_OP) {
+        continue;
+      }
+
+      if (NamePtr->Size != AML_NAME_DWORD_SIZE) {
+        continue;
+      }
+
+      NamePtr->Value = (UINT32) mNcpuValue[CpuSkt];
+      break;
+
+    case SIGNATURE_32 ('P', 'S', 'D', 'C'):
+    case SIGNATURE_32 ('P', 'S', 'D', 'E'):
+      PsdPackage = ACPI_NAME_COMMAND_FROM_NAME_STR (SsdtPointer);
+      if (PsdPackage->StartByte != AML_NAME_OP) {
+        continue;
+      }
+
+      PsdPackageItemPtr       = (PSD_PACKAGE_LAYOUT *) ((UINT8 *) PsdPackage);
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "PatchCpuPmSsdtTable(): PsdPackageItemPtr table: %x is detected...\n",
+        PsdPackage->NameStr
+        ));
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "   Initial Values:     Domain = %x,    CoordType = %x,   NumProcessors = %x\n",
+        PsdPackageItemPtr->Domain,
+        PsdPackageItemPtr->CoordType,
+        PsdPackageItemPtr->NumProcessors
+        ));
+
+      PsdPackageItemPtr->Domain = DomnValue;
+      PsdPackageItemPtr->NumProcessors = (UINT32) mNcpuValue[CpuSkt];
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "   PsdPackage = %x,    PsdPackageItemPtr = %x,   SsdtPointer = %x\n",
+        (UINT8 *)PsdPackage,
+        (UINT8 *)PsdPackageItemPtr,
+        (UINT8 *)SsdtPointer
+        ));
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "   Updated PSD Domain = %x,    CoordType = %x,   NumProcessors = %x\n",
+        PsdPackageItemPtr->Domain,
+        PsdPackageItemPtr->CoordType,
+        PsdPackageItemPtr->NumProcessors
+        ));
+      break;
+
+    default:
+      break;
+    } // switch
+  } // for
+
+  //
+  // N fixes together currently
+  //
+  ASSERT (CpuFixes == (UINT32) MAX_CPU_NUM);
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+    Update the OEM1 P-State SSDT table (EIST)
+
+    @param *TableHeader   - The table to be set
+
+    @retval EFI_SUCCESS -  Returns Success
+
+**/
+EFI_STATUS
+PatchOem1SsdtTable (
+  IN OUT   EFI_ACPI_COMMON_HEADER  *Table
+  )
+{
+  EFI_STATUS                  Status;
+  UINT8                       *CurrPtr;
+  UINT8                       *EndPtr;
+  UINT8                       *SsdtPointer;
+  UINT32                      Signature;
+  UINT32                      CpuFixes;
+  UINT32                      NpssFixes;
+  UINT32                      GpssFixes;
+  UINT32                      CpuSkt;
+  UINT32                      CpuIndex;
+  UINT32                      ThreadIndex;
+  UINT32                      PackageSize;
+  UINT32                      NewPackageSize;
+  UINT32                      AdjustSize;
+  UINTN                       TableIndex;
+  ACPI_NAME_COMMAND           *PssTable;
+  PSS_PACKAGE                 *PssTableItemPtr;
+  CPU_MISC_DATA               *CpuMiscData;
+  FVID_ENTRY                  *PssState;
+
+  DEBUG ((DEBUG_INFO, "Patching SSDT PatchOem1SsdtTable\n"));
+
+  //
+  // Loop through the ASL looking for values that we must fix up.
+  //
+  NpssFixes = 0;
+  GpssFixes = 0;
+  CpuFixes  = 0;
+  CpuSkt    = 0;
+  CpuIndex  = 0;
+  ThreadIndex  = 0;
+  CurrPtr = (UINT8 *) Table;
+  EndPtr  = (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length);
+  CpuMiscData = NULL;
+
+  Status = LocateCpuEistInfo (0, &CpuMiscData);   // get BSP's data
+  if( (EFI_ERROR (Status)) || (CpuMiscData == NULL ) ){
+    DEBUG ((DEBUG_WARN, " PatchGv3SsdtTable - EIST info for BSP index not found \n"));
+    return Status;
+  }
+
+  mPStateEnable = 1;
+
+  //
+  // CurrPtr = beginning of table to search
+  //
+  CurrPtr = SkipExternalSbOpcodes (CurrPtr, EndPtr, (UINT32) MAX_CPU_NUM);
+
+  //
+  // Subtract 11 from EndPtr - this is the size of the larget data item we will search for
+  // so that we do not try to read past the end of the table
+  //
+  EndPtr -= 11;
+
+  for (SsdtPointer = CurrPtr; SsdtPointer <= EndPtr; ++SsdtPointer) {
+    Signature = *(UINT32 *) SsdtPointer;
+    CpuIndex  = 0;
+    AdjustSize  = 0;
+
+    switch (Signature) {
+      case SIGNATURE_32 ('_', 'S', 'B', '_'):
+        //
+        // SKTX
+        //
+        CpuSkt = *(SsdtPointer + 7);
+        if ((CpuSkt < '0') || ((CpuSkt - '0') > MAX_SOCKET)) {
+          CpuSkt = '0';
+        }
+
+        CpuSkt -= '0';
+
+        if ((*(SsdtPointer + 11) > '0') && (*(SsdtPointer + 11) <= '9')) {
+          CpuIndex = (*(SsdtPointer + 11) -'0');
+        } else if ((*(SsdtPointer + 11) >= 'A') && (*(SsdtPointer + 11) <= 'F')) {
+          CpuIndex = (*(SsdtPointer + 11) -'A' + 10);
+        }
+
+        if ((*(SsdtPointer + 10) > '0') && ( *(SsdtPointer + 10) <= '9')) {
+          AdjustSize = (*(SsdtPointer + 10) -'0') * 0x10;
+        } else if ((*(SsdtPointer + 10) >= 'A') && (*(SsdtPointer + 10) <= 'F')) {
+          AdjustSize = (*(SsdtPointer + 10) -'A' + 10) * 0x10;
+        }
+
+        CpuIndex += AdjustSize;
+        AdjustSize  = 0;
+
+        if ((*(SsdtPointer + 9) > '0') && (*(SsdtPointer + 9) <= '9')) {
+          AdjustSize = (*(SsdtPointer + 9) -'0') * 0x100;
+        } else if ((*(SsdtPointer + 9) >= 'A') && (*(SsdtPointer + 9) <= 'F')) {
+          AdjustSize = (*(SsdtPointer + 9) -'A' + 10) * 0x100;
+        }
+
+        CpuIndex += AdjustSize;
+        ThreadIndex  = CpuIndex;
+
+        ++CpuFixes;
+        CpuMiscData = NULL;
+        LocateCpuEistInfo (0, &CpuMiscData);  // use CPU0 for update NPSS and SPSS
+        break;
+
+      case SIGNATURE_32 ('N', 'P', 'S', 'S'):
+      case SIGNATURE_32 ('S', 'P', 'S', 'S'):
+
+        PssTable = ACPI_NAME_COMMAND_FROM_NAME_STR (SsdtPointer);
+        if (PssTable->StartByte != AML_NAME_OP) {
+          continue;
+        }
+
+        ASSERT (CpuMiscData != NULL);
+        PssState = CpuMiscData->FvidTable;
+
+        AdjustSize  = PssTable->NumEntries * sizeof (PSS_PACKAGE);
+        AdjustSize -= (UINT32)(CpuMiscData->NumberOfPStates * sizeof (PSS_PACKAGE));
+        PackageSize     = (PssTable->Size & 0xF) + ((PssTable->Size & 0xFF00) >> 4);
+        NewPackageSize  = PackageSize - AdjustSize;
+        PssTable->Size  = (UINT16) ((NewPackageSize & 0xF) + ((NewPackageSize & 0x0FF0) << 4));
+
+        //
+        // Set most significant two bits of byte zero to 01, meaning two bytes used
+        //
+        PssTable->Size |= 0x40;
+
+        //
+        // Set unused table to Noop Code
+        //
+        SetMem (
+          (UINT8 *) PssTable + NewPackageSize + AML_NAME_PREFIX_SIZE,
+          AdjustSize,
+          AML_NOOP_OP
+          );
+        PssTable->NumEntries  = (UINT8) CpuMiscData->NumberOfPStates;
+        PssTableItemPtr       = (PSS_PACKAGE *) ((UINT8 *) PssTable + sizeof (ACPI_NAME_COMMAND));
+
+        //
+        // Update the size
+        //
+
+        if (CpuMiscData->NumberOfPStates == 1) {
+          mPStateEnable = 0;
+        }
+
+        for (TableIndex = 0; TableIndex < CpuMiscData->NumberOfPStates; ++TableIndex) {
+          PssTableItemPtr->CoreFreq = (UINT32) (CpuMiscData->IntendedFsbFrequency * PssState[TableIndex].Ratio);
+          if (mSocketPowermanagementConfiguration.TurboMode && (TableIndex == 0) && IsTurboModeEnabled ()) {
+            PssTableItemPtr->CoreFreq = (UINT32)((CpuMiscData->IntendedFsbFrequency * PssState[TableIndex + 1].Ratio) + 1);
+          }
+
+
+          PssTableItemPtr->Power    =  (UINT32)(PssState[TableIndex].Power); // when calulate Tdp already make it mW;
+          if (PssTable->NameStr == SIGNATURE_32 ('N', 'P', 'S', 'S')) {
+            PssTableItemPtr->TransLatency = (UINT32)(PssState[TableIndex].TransitionLatency);
+              PssTableItemPtr->Control  = (UINT32)(PssState[TableIndex].Ratio << 8);
+              PssTableItemPtr->Status   = (UINT32)(PssState[TableIndex].Ratio << 8);
+          } else {
+            //
+            // This method should be supported by SMM PPM Handler
+            //
+            // Status is simply the state number.
+            // Use the state number w/ OS command value so that the
+            // legacy interface may be used.  Latency for SMM is 100 + BM latency.
+            PssTableItemPtr->Status   = (UINT32)TableIndex;
+            PssTableItemPtr->TransLatency = (UINT32)(100 + PssState[TableIndex].TransitionLatency);
+            PssTableItemPtr->Control  = (UINT32)(SW_SMI_OS_REQUEST | (TableIndex << 8));
+          }
+
+          PssTableItemPtr->BMLatency    = (UINT32)(PssState[TableIndex].BusMasterLatency);
+
+          ++PssTableItemPtr;
+        }
+
+        if (PssTable->NameStr == SIGNATURE_32 ('N', 'P', 'S', 'S')) {
+          ++NpssFixes;
+        }
+
+        SsdtPointer = (UINT8 *) PssTable + PackageSize;
+        break;
+
+      case SIGNATURE_32 ('G', 'P', 'S', 'S'):
+
+        PssTable = ACPI_NAME_COMMAND_FROM_NAME_STR (SsdtPointer);
+        if (PssTable->StartByte != AML_NAME_OP) {
+          continue;
+        }
+
+        ASSERT (CpuMiscData != NULL);
+        PssState = CpuMiscData->GreaterFvidTable;
+
+        ASSERT (CpuMiscData->GreaterNumberOfPStates <= GPSS_FVID_MAX_STATES);
+        if (CpuMiscData->GreaterNumberOfPStates > GPSS_FVID_MAX_STATES) {
+          continue;
+        }
+
+        AdjustSize  = PssTable->NumEntries * sizeof (PSS_PACKAGE);
+        AdjustSize -= (UINT32)(CpuMiscData->GreaterNumberOfPStates * sizeof (PSS_PACKAGE));
+        PackageSize     = (PssTable->Size & 0xF) + ((PssTable->Size & 0xFF00) >> 4);
+        NewPackageSize  = PackageSize - AdjustSize;
+        PssTable->Size  = (UINT16) ((NewPackageSize & 0xF) + ((NewPackageSize & 0x0FF0) << 4));
+
+        //
+        // Set most significant two bits of byte zero to 01, meaning two bytes used
+        //
+        PssTable->Size |= 0x40;
+
+        //
+        // Set unused table to Noop Code
+        //
+        SetMem (
+          (UINT8 *) PssTable + NewPackageSize + AML_NAME_PREFIX_SIZE,
+          AdjustSize,
+          AML_NOOP_OP
+          );
+        PssTable->NumEntries  = (UINT8) CpuMiscData->GreaterNumberOfPStates;
+        PssTableItemPtr       = (PSS_PACKAGE *) ((UINT8 *) PssTable + sizeof (ACPI_NAME_COMMAND));
+
+        //
+        // Update the size
+        //
+        for (TableIndex = 0; TableIndex < CpuMiscData->GreaterNumberOfPStates; ++TableIndex) {
+          PssTableItemPtr->CoreFreq = (UINT32) (CpuMiscData->IntendedFsbFrequency * PssState[TableIndex].Ratio);
+          if (mSocketPowermanagementConfiguration.TurboMode && (TableIndex == 0) && IsTurboModeEnabled()) {
+            PssTableItemPtr->CoreFreq = (UINT32)((CpuMiscData->IntendedFsbFrequency * PssState[TableIndex + 1].Ratio) + 1);
+          }
+
+          //
+          // If Turbo mode is supported, add one to the Max Non-Turbo frequency
+          //
+          PssTableItemPtr->Power = (UINT32)(PssState[TableIndex].Power); // when calulate Tdp already make it mW;
+          if (PssTable->NameStr == SIGNATURE_32 ('G', 'P', 'S', 'S')) {
+            PssTableItemPtr->TransLatency = (UINT32)(PssState[TableIndex].TransitionLatency);
+            PssTableItemPtr->Control  = (UINT32)(PssState[TableIndex].Ratio << 8);
+            PssTableItemPtr->Status   = (UINT32)(PssState[TableIndex].Ratio << 8);
+          } else {
+            //
+            // This method should be supported by SMM PPM Handler
+            //
+            // Status is simply the state number.
+            // Use the state number w/ OS command value so that the
+            // legacy interface may be used.  Latency for SMM is 100 + BM latency.
+            //
+            PssTableItemPtr->Status   = (UINT32)TableIndex;
+            PssTableItemPtr->TransLatency = (UINT32)(100 + PssState[TableIndex].TransitionLatency);
+            PssTableItemPtr->Control  = (UINT32)(SW_SMI_OS_REQUEST | (TableIndex << 8));
+          }
+
+          PssTableItemPtr->BMLatency    = (UINT32)(PssState[TableIndex].BusMasterLatency);
+
+          ++PssTableItemPtr;
+        }
+
+        if (PssTable->NameStr == SIGNATURE_32 ('G', 'P', 'S', 'S')) {
+          ++GpssFixes;
+        }
+
+        SsdtPointer = (UINT8 *) PssTable + PackageSize;
+        break;
+
+      default:
+        break;
+    } // switch
+  } // for
+
+  //
+  // N fixes together currently
+  //
+  ASSERT (CpuFixes == (UINT32) MAX_CPU_NUM);
+
+  if (!mPStateEnable || !mSocketPowermanagementConfiguration.ProcessorEistEnable || (mSocketPowermanagementConfiguration.ProcessorHWPMEnable > HWP_MODE_NATIVE) ) {
+      Status = EFI_UNSUPPORTED;  //CPU EIST
+      return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+PatchSsdtTable (
+  IN OUT EFI_ACPI_COMMON_HEADER     *Table,
+  IN OUT EFI_ACPI_TABLE_VERSION     *Version
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_ACPI_DESCRIPTION_HEADER   *TableHeader;
+
+  Status = EFI_SUCCESS;
+  TableHeader = (EFI_ACPI_DESCRIPTION_HEADER   *)Table;
+
+    //
+    // Do not load the xHCI table. It is handled by separate function.
+    //
+    TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table;
+    if (CompareMem (&TableHeader->OemTableId, "xh_", 3) == 0) {
+      DEBUG ((DEBUG_ERROR,"Xhci TableHeader->OemTableId = %x\n ", TableHeader->OemTableId));
+      *Version = EFI_ACPI_TABLE_VERSION_NONE;
+    }
+
+    if (TableHeader->OemTableId == SIGNATURE_64 ('S', 'S', 'D', 'T', ' ', ' ', 'P', 'M')) {
+      PatchCpuPmSsdtTable (Table);  //CPU PM
+    }
+
+  return Status;
+}
+
+/**
+  Update the OEM2 HWP SSDT table if needed
+
+  @param *TableHeader   - The table to be set
+
+  @retval EFI_SUCCESS -  Returns Success
+**/
+EFI_STATUS
+PatchOem2SsdtTable (
+  IN OUT   EFI_ACPI_COMMON_HEADER  *Table
+  )
+{
+  EFI_STATUS    Status = EFI_SUCCESS;
+
+  if ((mSocketPowermanagementConfiguration.ProcessorHWPMEnable == 0) || (mSocketPowermanagementConfiguration.ProcessorHWPMEnable == HWP_MODE_OOB)) {
+    Status = EFI_UNSUPPORTED;
+  }
+
+  return Status;
+}
+
+/**
+  Update the OEM3 T-State SSDT table (TST)
+
+  @param *TableHeader   - The table to be set
+
+  @retval EFI_SUCCESS -  Returns Success
+**/
+EFI_STATUS
+PatchOem3SsdtTable (
+  IN OUT   EFI_ACPI_COMMON_HEADER  *Table
+  )
+{
+  UINT8                       *CurrPtr;
+  UINT8                       *EndPtr;
+  UINT8                       *SsdtPointer;
+  UINT32                      Signature;
+  UINT32                      CpuFixes;
+  UINT32                      CpuSkt;
+  UINT32                      CpuIndex;
+  UINT32                      ThreadIndex;
+  UINT32                      AdjustSize;
+  UINT32                      DomnValue;
+  ACPI_NAME_COMMAND           *PsdPackage;
+  PSD_PACKAGE_LAYOUT          *PsdPackageItemPtr;
+
+  DEBUG ((DEBUG_INFO, "Patching SSDT PatchOem3SsdtTable\n"));
+
+  if (!mSocketPowermanagementConfiguration.TStateEnable || (mSocketPowermanagementConfiguration.ProcessorHWPMEnable > HWP_MODE_NATIVE) ) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Loop through the ASL looking for values that we must fix up.
+  //
+  DomnValue = 0;
+  CpuFixes  = 0;
+  CpuSkt    = 0;
+  ThreadIndex  = 0;
+  CurrPtr = (UINT8 *) Table;
+  EndPtr  = (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length);
+
+  //
+  // CurrPtr = beginning of table we want to search
+  //
+  CurrPtr = SkipExternalSbOpcodes(CurrPtr, EndPtr, (UINT32) MAX_CPU_NUM);
+
+  //
+  // Subtract 11 from EndPtr - this is the size of the larget data item we will read
+  //  so that we don't read beyond the end of the table
+  //
+  EndPtr -= 11;
+
+  for (SsdtPointer = CurrPtr; SsdtPointer <= EndPtr; ++SsdtPointer) {
+    Signature = *(UINT32 *) SsdtPointer;
+    CpuIndex  = 0;
+    AdjustSize  = 0;
+
+    switch (Signature) {
+
+    case SIGNATURE_32 ('_', 'S', 'B', '_'):
+      //
+      // SKTX
+      //
+      CpuSkt = *(SsdtPointer + 7);
+      CpuSkt -= '0';
+
+      if ((*(SsdtPointer + 8) != 'C')) {
+        continue;
+      }
+
+      if ((*(SsdtPointer + 11) > '0') && (*(SsdtPointer + 11) <= '9')) {
+        CpuIndex = (*(SsdtPointer + 11) -'0');
+      } else if ((*(SsdtPointer + 11) >= 'A') && (*(SsdtPointer + 11) <= 'F')) {
+        CpuIndex = (*(SsdtPointer + 11) -'A' + 10);
+      }
+
+      if ((*(SsdtPointer + 10) > '0') && ( *(SsdtPointer + 10) <= '9')) {
+        AdjustSize = (*(SsdtPointer + 10) -'0') * 0x10;
+      } else if ((*(SsdtPointer + 10) >= 'A') && (*(SsdtPointer + 10) <= 'F')) {
+        AdjustSize = (*(SsdtPointer + 10) -'A' + 10) * 0x10;
+      }
+
+      CpuIndex += AdjustSize;
+      AdjustSize  = 0;
+
+      if ((*(SsdtPointer + 9) > '0') && (*(SsdtPointer + 9) <= '9')) {
+        AdjustSize = (*(SsdtPointer + 9) -'0') * 0x100;
+      } else if ((*(SsdtPointer + 9) >= 'A') && (*(SsdtPointer + 9) <= 'F')) {
+        AdjustSize = (*(SsdtPointer + 9) -'A' + 10) * 0x100;
+      }
+
+      CpuIndex += AdjustSize;
+      ThreadIndex = CpuIndex;
+
+      //
+      // PCPS - Update DOMN
+      //
+      DomnValue = (UINT8) CpuSkt;
+
+      if ((mCpuPCPSInfo[CpuSkt] & B_PCPS_DISABLE) == 0) {
+        DomnValue = LocateApicIdInfo (CpuSkt, ThreadIndex);
+
+        if (mNcpuValue[CpuSkt] == 2) {
+          DomnValue = (DomnValue >> 1);
+        }
+      }
+
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "PatchOem3SsdtTable(): CpuIndex: 0x%x ThreadIndex: 0x%x CpuFixes: 0x%x (%d)\n",
+        CpuIndex,
+        ThreadIndex,
+        CpuFixes,
+        CpuFixes
+        ));
+
+      DEBUG ((
+        DEBUG_INFO,
+        "PatchOem3SsdtTable(): CpuSkt: %d CpuIndex: 0x%x, NcpuValue = 0x%x, DomnValue = 0x%x\n",
+        CpuSkt,
+        CpuIndex,
+        mNcpuValue[CpuSkt],
+        DomnValue
+        ));
+      ++CpuFixes;
+      break;
+
+    case SIGNATURE_32 ('T', 'S', 'D', 'C'):
+    case SIGNATURE_32 ('T', 'S', 'D', 'D'):
+      PsdPackage = ACPI_NAME_COMMAND_FROM_NAME_STR (SsdtPointer);
+      if (PsdPackage->StartByte != AML_NAME_OP) {
+        continue;
+      }
+
+      PsdPackageItemPtr       = (PSD_PACKAGE_LAYOUT *) ((UINT8 *) PsdPackage);
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "TSDC: PsdPackageItemPtr table: %x is detected...\n",
+        PsdPackage->NameStr
+        ));
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "   Initial Values:     Domain = %x,    CoordType = %x,   NumProcessors = %x\n",
+        PsdPackageItemPtr->Domain,
+        PsdPackageItemPtr->CoordType,
+        PsdPackageItemPtr->NumProcessors
+        ));
+
+      PsdPackageItemPtr->Domain = DomnValue;
+      PsdPackageItemPtr->NumProcessors = mNcpuValue[CpuSkt];
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "   PsdPackage = %x,    PsdPackageItemPtr = %x,   SsdtPointer = %x\n",
+        (UINT8 *)PsdPackage,
+        (UINT8 *)PsdPackageItemPtr,
+        (UINT8 *)SsdtPointer
+        ));
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "   Updated TSD Domain = %x,    CoordType = %x,   NumProcessors = %x\n",
+        PsdPackageItemPtr->Domain,
+        PsdPackageItemPtr->CoordType,
+        PsdPackageItemPtr->NumProcessors
+        ));
+      break;
+
+    default:
+      break;
+    } // switch
+  } // for
+
+  //
+  // N fixes together currently
+  //
+  ASSERT (CpuFixes == (UINT32) MAX_CPU_NUM);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Update the OEM4 C State SSDT table (CST)
+
+  @param *TableHeader   - The table to be set
+
+  @retval EFI_SUCCESS -  Returns Success
+**/
+EFI_STATUS
+PatchOem4SsdtTable (
+  IN OUT   EFI_ACPI_COMMON_HEADER  *Table
+  )
+{
+  return EFI_SUCCESS;
+}

+ 5 - 0
Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dec

@@ -398,6 +398,11 @@
   ##
   gPlatformModuleTokenSpaceGuid.PcdEnableHighSpeedUart|FALSE|BOOLEAN|0x0000002C
 
+  ## Platform Not support Acpi Table
+  #
+  gPlatformTokenSpaceGuid.PcdPlatformNotSupportAcpiTable|FALSE|BOOLEAN|0x40000012
+  gPlatformTokenSpaceGuid.PcdPlatformNotSupportAcpiBdatTable|FALSE|BOOLEAN|0x40000013
+
 [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamicEx]
   ## MemoryCheck value for checking memory before boot OS.
   #  To save the boot performance, the default MemoryCheck is set to 0.

+ 1 - 0
Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dsc

@@ -621,6 +621,7 @@
   CrcLib|WhitleyOpenBoardPkg/Library/BaseCrcLib/BaseCrcLib.inf
   PlatformSpecificAcpiTableLib|WhitleyOpenBoardPkg/Library/PlatformSpecificAcpiTableLibNull/PlatformSpecificAcpiTableLibNull.inf
   BuildAcpiTablesLib|WhitleyOpenBoardPkg/Library/BuildAcpiTablesLib/DxeBuildAcpiTablesLib.inf
+  AcpiPlatformTableLib|WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLib.inf
 
 [LibraryClasses.Common.SEC, LibraryClasses.Common.PEI_CORE, LibraryClasses.Common.PEIM]
   FspWrapperApiLib|IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/BaseFspWrapperApiLib.inf