/** @file
  This file contains the tests for the SecureMemoryMapConfiguration bit

Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
Copyright (c) Microsoft Corporation.<BR>

SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "HstiSiliconDxe.h"
#include <Guid/FlashRegion.h>

typedef struct {
  UINT64   Base;
  UINT64   End;
} MEMORY_RANGE;

typedef enum {
  LockableMemoryRangeLtSpace,
  LockableMemoryRangeHighBios,
  LockableMemoryRangeLowDram,
  LockableMemoryRangeHighDram,
  LockableMemoryRangeMchBar,
  LockableMemoryRangeDmiBar,
  LockableMemoryRangePxpEpBar,
  LockableMemoryRangeGfxVtBar,
  LockableMemoryRangeVtdPvc0Bar,
  LockableMemoryRangeGdxcBar,
  LockableMemoryRangeEdramBar,
  LockableMemoryRangeCpuRsvd1Bar,
  LockableMemoryRangeCpuRsvd2Bar,
  LockableMemoryRangeMax,
} LOCKABLE_MEMORY_RAMGE;

MEMORY_RANGE  mLockableMemoryRange[LockableMemoryRangeMax] = {
  // 1. LT space (0xFED20000 - 0xFED7FFFF)
  {0xFED20000, 0xFED7FFFF},
  // 2. High BIOS
  {0x0, SIZE_4GB - 1},
  // 3. Low DRAM (0 - TOLUD)
  {0x0, 0},
  // 4. High DRAM (4GB - TOUUD)
  {SIZE_4GB, 0},
  // 5. MCHBAR
  {0, 0},
  // 6. DMIBAR
  {0, 0},
  // 7. PXPEPBAR
  {0, 0},
  // 8. GFXVTBAR
  {0, 0},
  // 9. VTDPVC0BAR
  {0, 0},
  // 10. GDXCBAR
  {0, 0},
  // 11. EDRAMBAR (MCHBAR + 0x5408)
  {0, 0},
  // 12. CPU Reserved space: 0xFEB00000 to 0xFEB0FFFF
  {0xFEB00000, 0xFEB0FFFF},
  // 13. CPU Reserved space: 0xFEB80000 to 0xFEB8FFFF
  {0xFEB80000, 0xFEB8FFFF},
};

typedef enum {
  NonLockableMemoryRangeMBASE0,
  NonLockableMemoryRangePMBASE0,
  NonLockableMemoryRangePMBASEU0,
  NonLockableMemoryRangeMBASE1,
  NonLockableMemoryRangePMBASE1,
  NonLockableMemoryRangePMBASEU1,
  NonLockableMemoryRangeMBASE2,
  NonLockableMemoryRangePMBASE2,
  NonLockableMemoryRangePMBASEU2,
  NonLockableMemoryRangeGTTMMADR,
  NonLockableMemoryRangeGMADR,
  NonLockableMemoryRangeTMBAR,
  NonLockableMemoryRangeABAR,
  NonLockableMemoryRangeSBREG_BAR,
  NonLockableMemoryRangePWRMBASE,
  NonLockableMemoryRangeSPI_BAR0,
  NonLockableMemoryRangeMax,
} NONLOCKABLE_MEMORY_RAMGE;

MEMORY_RANGE  mNonLockableMemoryRange[NonLockableMemoryRangeMax] = {
  {0, 0},
// 1.  Local Apic for each CPU thread (IA32_APICBASE MSR 0x1B)
// 2.  MBASE0,  (PEG) BDF 0:1:0  + 0x20
// 3.  PMBASE0, (PEG) BDF 0:1:0  + 0x24 LOW
//                    BDF 0:1:1  + 0x28 HIGH
// 4.  MBASE1,  (PEG) BDF 0:1:1  + 0x20
// 5.  PMBASE1, (PEG) BDF 0:1:1  + 0x24 LOW
//                    BDF 0:1:1  + 0x28 HIGH
// 6.  MBASE2,  (PEG) BDF 0:1:2  + 0x20
// 7.  PMBASE2, (PEG) BDF 0:1:2  + 0x24 LOW
//                    BDF 0:1:1  + 0x28 HIGH
// 8.  GTTMMADR,      BDF 0:2:0  + 0x10
// 9.  GMADR,         BDF 0:2:0  + 0x18 (Need to account for MSAC)
// 10. TMBAR,         BDF 0:4:0  + 0x10 (if Device 4 is enabled in BDF 0:0:0 + 0x54[7])
// 11. ABAR,          BDF 0:31:2 + 0x24
// 12. SBREG_BAR (BDF 0:31:1 + 0x10)
// 13. PWRMBASE (BDF 0:31:2 + 0x48)
// 14. SPI_BAR0 (BDF 0:31:5 + 0x10)
};

typedef enum {
  FlashRegionDescriptor,
  FlashRegionBios,
  FlashRegionMe,
  FlashRegionGbe,
  FlashRegionPlatformData,
  FlashRegionDer,
  FlashRegionAll,
  FlashRegionMax
} FLASH_REGION_TYPE;

typedef struct {
  EFI_GUID            *Guid;
  FLASH_REGION_TYPE   Type;
} FLASH_REGION_MAPPING;

FLASH_REGION_MAPPING mFlashRegionTypes[] = {
  {
    &gFlashRegionDescriptorGuid,
    FlashRegionDescriptor
  },
  {
    &gFlashRegionBiosGuid,
    FlashRegionBios
  },
  {
    &gFlashRegionMeGuid,
    FlashRegionMe
  },
  {
    &gFlashRegionGbeGuid,
    FlashRegionGbe
  },
  {
    &gFlashRegionPlatformDataGuid,
    FlashRegionPlatformData
  },
  {
    &gFlashRegionDerGuid,
    FlashRegionDer
  },
  {
    &gFlashRegionAllGuid,
    FlashRegionAll
  },
  {
    &gFlashRegionMaxGuid,
    FlashRegionMax
  }
};

/**
  Returns the type of a flash region given its GUID.

  @param[in]    FlashRegionGuid   Pointer to the flash region GUID.
  @param[out]   FlashRegionType   Pointer to a buffer that will be set to the flash region type value.

  @retval       EFI_SUCCESS             The flash region type was found for the given flash region GUID.
  @retval       EFI_INVALID_PARAMETER   A pointer argument passed to the function is NULL.
  @retval       EFI_NOT_FOUND           The flash region type was not found for the given flash region GUID.

**/
EFI_STATUS
GetFlashRegionType (
  IN     EFI_GUID           *FlashRegionGuid,
  OUT    FLASH_REGION_TYPE  *FlashRegionType
  )
{
  UINTN   Index;

  if (FlashRegionGuid == NULL || FlashRegionType == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  for (Index = 0; Index < ARRAY_SIZE (mFlashRegionTypes); Index++) {
    if (CompareGuid (mFlashRegionTypes[Index].Guid, FlashRegionGuid)) {
      *FlashRegionType = mFlashRegionTypes[Index].Type;
      return EFI_SUCCESS;
    }
  }

  return EFI_NOT_FOUND;
}

/**
  Check for overlaps in single range array

  @param[in] Range     - Pointer to Range array
  @param[in] Count     - Number of Enties

  @retval BOOLEAN - Overlap Exists
**/
BOOLEAN
CheckOverlap (
  IN MEMORY_RANGE *Range,
  IN UINTN        Count
  )
{
  UINTN  Index;
  UINTN  SubIndex;

  for (Index = 0; Index < Count - 1; Index++) {
    if ((Range[Index].Base == 0) && (Range[Index].End == 0)) {
      continue;
    }
    for (SubIndex = Index + 1; SubIndex < Count; SubIndex++) {
      if ((Range[SubIndex].Base == 0) && (Range[SubIndex].End == 0)) {
        continue;
      }
      if (((Range[Index].Base >= Range[SubIndex].Base) && (Range[Index].Base <= Range[SubIndex].End)) ||
          ((Range[SubIndex].Base >= Range[Index].Base) && (Range[SubIndex].Base <= Range[Index].End))) {
        DEBUG ((DEBUG_ERROR, "OVERLAP: \n"));
        DEBUG ((DEBUG_ERROR, "  0x%016lx - 0x%016lx\n", Range[Index].Base, Range[Index].End));
        DEBUG ((DEBUG_ERROR, "  0x%016lx - 0x%016lx\n", Range[SubIndex].Base, Range[SubIndex].End));
        return TRUE;
      }
    }
  }

  DEBUG ((DEBUG_INFO, "CheckOverlap: PASS\n"));
  return FALSE;
}

/**
  Check for overlaps between two arrays of memory ranges

  @param[in] Range1     - Pointer to Range1 array
  @param[in] Count1     - Number of Enties
  @param[in] Range2     - Pointer to Range2 array
  @param[in] Count2     - Number of Enties

  @retval BOOLEAN - Overlap Exists
**/
BOOLEAN
CheckOverlap2 (
  IN MEMORY_RANGE *Range1,
  IN UINTN        Count1,
  IN MEMORY_RANGE *Range2,
  IN UINTN        Count2
  )
{
  UINTN  Index1;
  UINTN  Index2;

  for (Index1 = 0; Index1 < Count1; Index1++) {
    if ((Range1[Index1].Base == 0) && (Range1[Index1].End == 0)) {
      continue;
    }
    for (Index2 = 0; Index2 < Count2; Index2++) {
      if ((Range2[Index2].Base == 0) && (Range2[Index2].End == 0)) {
        continue;
      }
      if (((Range1[Index1].Base >= Range2[Index2].Base) && (Range1[Index1].Base <= Range2[Index2].End)) ||
          ((Range2[Index2].Base >= Range1[Index1].Base) && (Range2[Index2].Base <= Range1[Index1].End))) {
        DEBUG ((DEBUG_ERROR, "OVERLAP2: \n"));
        DEBUG ((DEBUG_ERROR, "  0x%016lx - 0x%016lx\n", Range1[Index1].Base, Range1[Index1].End));
        DEBUG ((DEBUG_ERROR, "  0x%016lx - 0x%016lx\n", Range2[Index2].Base, Range2[Index2].End));
        return TRUE;
      }
    }
  }

  DEBUG ((DEBUG_INFO, "CheckOverlap2: PASS\n"));
  return FALSE;
}

/**
  Dumps Ranges to Serial

  @param[in] Range     - Pointer to Range array
  @param[in] Count     - Number of Enties

**/
VOID
DumpRange (
  IN MEMORY_RANGE *Range,
  IN UINTN        Count
  )
{
  UINTN  Index;

  for (Index = 0; Index < Count; Index ++) {
    DEBUG ((DEBUG_INFO, "  [%02d] 0x%016lx - 0x%016lx\n", Index, Range[Index].Base, Range[Index].End));
  }
}
//
// mPchSpiResvMmioAddr keeps the reserved MMIO range assiged to SPI.
// In SMM it always set back the reserved MMIO address to SPI BAR0 to ensure the MMIO range
// won't overlap with SMRAM range, and trusted.
//
GLOBAL_REMOVE_IF_UNREFERENCED UINT32                mSpiResvMmioAddr;

/**
  Acquire PCH spi mmio address.
  It is not expected for this BAR0 to change because the SPI device is hidden
  from the OS for SKL PCH LP/H B stepping and above (refer to section 3.5.1),
  but if it is ever different from the preallocated address, reassign it back.
  In SMM, it always override the BAR0 and returns the reserved MMIO range for SPI.

  @retval PchSpiBar0              return SPI MMIO address
**/
UINTN
AcquireSpiBar0 (
  VOID
  )
{
  UINT32                          SpiBar0;
  UINTN                           PchSpiBase;

  //
  // Init PCH spi reserved MMIO address.
  //
  mSpiResvMmioAddr = PCH_SPI_BASE_ADDRESS;

  PchSpiBase = MmPciBase (
                              DEFAULT_PCI_BUS_NUMBER_PCH,
                              PCI_DEVICE_NUMBER_PCH_SPI,
                              PCI_FUNCTION_NUMBER_PCH_SPI
                              );
  //
  // Save original SPI physical MMIO address
  //
  SpiBar0 = MmioRead32 (PchSpiBase + R_PCH_SPI_BAR0) & ~(B_PCH_SPI_BAR0_MASK);

  if (SpiBar0 != mSpiResvMmioAddr) {
    //
    // Temporary disable MSE, and override with SPI reserved MMIO address, then enable MSE.
    //
    MmioAnd8 (PchSpiBase + PCI_COMMAND_OFFSET, (UINT8) ~EFI_PCI_COMMAND_MEMORY_SPACE);
    MmioWrite32 (PchSpiBase + R_PCH_SPI_BAR0, mSpiResvMmioAddr);
    MmioOr8 (PchSpiBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
  }
  //
  // SPIBAR0 will be different before and after PCI enum so need to get it from SPI BAR0 reg.
  //
  return mSpiResvMmioAddr;
}

/**
  Release pch spi mmio address. Do nothing.

  @retval None
**/
VOID
ReleaseSpiBar0 (
  VOID
  )
{
}

/**
  Get the SPI region base and size, based on the enum type

  @param[in] This                 Pointer to the PCH_SPI2_PROTOCOL instance.
  @param[in] FlashRegionGuid      The Flash Region GUID for the base address which corresponds to the type in the descriptor.
  @param[out] BaseAddress         The Flash Linear Address for the Region 'n' Base
  @param[out] RegionSize          The size for the Region 'n'

  @retval EFI_SUCCESS             Read success
  @retval EFI_INVALID_PARAMETER   Invalid region type given
  @retval EFI_DEVICE_ERROR        The region is not used
**/
EFI_STATUS
EFIAPI
GetRegionAddress (
  IN     EFI_GUID           *FlashRegionGuid,
  OUT    UINT32             *BaseAddress,
  OUT    UINT32             *RegionSize
  )
{
  EFI_STATUS          Status;
  FLASH_REGION_TYPE   FlashRegionType;
  UINTN               PchSpiBar0;
  UINT32              ReadValue;

  Status = GetFlashRegionType (FlashRegionGuid, &FlashRegionType);
  if (EFI_ERROR (Status)) {
    return EFI_INVALID_PARAMETER;
  }

  if (FlashRegionType >= FlashRegionMax) {
    return EFI_INVALID_PARAMETER;
  }

  if (FlashRegionType == FlashRegionAll) {
    return EFI_UNSUPPORTED;
  }

  PchSpiBar0      = AcquireSpiBar0 ();
  ReadValue = MmioRead32 (PchSpiBar0 + (R_PCH_SPI_FREG0_FLASHD + (S_PCH_SPI_FREGX * ((UINT32) FlashRegionType))));
  ReleaseSpiBar0 ();

  //
  // If the region is not used, the Region Base is 7FFFh and Region Limit is 0000h
  //
  if (ReadValue == B_PCH_SPI_FREGX_BASE_MASK) {
    return EFI_DEVICE_ERROR;
  }
  *BaseAddress = ((ReadValue & B_PCH_SPI_FREGX_BASE_MASK) >> N_PCH_SPI_FREGX_BASE) <<
    N_PCH_SPI_FREGX_BASE_REPR;
  //
  // Region limit address Bits[11:0] are assumed to be FFFh
  //
  *RegionSize = ((((ReadValue & B_PCH_SPI_FREGX_LIMIT_MASK) >> N_PCH_SPI_FREGX_LIMIT) + 1) <<
                 N_PCH_SPI_FREGX_LIMIT_REPR) - *BaseAddress;

  return EFI_SUCCESS;
}

/**
  Run tests for SecureMemoryMapConfiguration bit
**/
VOID
CheckSecureMemoryMapConfiguration (
  VOID
  )
{
  EFI_STATUS        Status;
  BOOLEAN           Result;
  UINT32            MchBar;
  UINT32            Dpr;
  UINT32            MeSegMask;
  UINT64            RemapBase;
  UINT64            RemapLimit;
  UINT32            Tom;
  UINT32            Touud;
  UINT32            Tolud;
  UINT64            Data64;
  UINT32            ApertureSize;
  UINT8             Msac;
  CHAR16            *HstiErrorString;
  UINT32            BarRead;
  UINT16            VendorIdRead;
  UINTN             PchSpiBase;
  UINT32            PwrmBase;
  UINT32            AbarSize;
  UINT32            BaseAddress;
  UINT32            RegionSize;

  if ((mFeatureImplemented[1] & HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION) == 0) {
    return;
  }

  Result = TRUE;

  MchBar = (UINT32) MmioRead64 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_MC_DEV,SA_MC_FUN) + R_SA_MCHBAR) & B_SA_MCHBAR_MCHBAR_MASK;

  DEBUG ((DEBUG_INFO, "  Table 3-3. Memory Map Secure Configuration\n"));

  DEBUG ((DEBUG_INFO, "    1. DPR\n"));

  Dpr = MmioRead32 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_MC_DEV,SA_MC_FUN) + R_SA_DPR);

  if ((Dpr & B_SA_DPR_LOCK_MASK) == 0) {
    DEBUG ((DEBUG_INFO, "Fail: DPR not locked\n"));

    HstiErrorString = BuildHstiErrorString (HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_CODE_1 ,HSTI_MEMORY_MAP_SECURITY_CONFIGURATION, HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_STRING_1);
    Status = HstiLibAppendErrorString (
               PLATFORM_SECURITY_ROLE_PLATFORM_REFERENCE,
               NULL,
               HstiErrorString
               );
    ASSERT_EFI_ERROR (Status);
    Result = FALSE;
    FreePool (HstiErrorString);
  }

  DEBUG ((DEBUG_INFO, "    2. MESEG\n"));
  MeSegMask =  MmioRead32 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_MC_DEV,SA_MC_FUN) + R_SA_MESEG_MASK);

  if ((MeSegMask & B_SA_MESEG_MASK_MELCK_MASK) == 0) {
    DEBUG ((DEBUG_INFO, "Fail: MESEG not locked\n"));

    HstiErrorString = BuildHstiErrorString (HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_CODE_1 ,HSTI_MEMORY_MAP_SECURITY_CONFIGURATION, HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_STRING_1);
    Status = HstiLibAppendErrorString (
               PLATFORM_SECURITY_ROLE_PLATFORM_REFERENCE,
               NULL,
               HstiErrorString
               );
    ASSERT_EFI_ERROR (Status);
    Result = FALSE;
    FreePool (HstiErrorString);
  }

  DEBUG ((DEBUG_INFO, "    3. REMAPBASE\n"));

  RemapBase = MmioRead64 (MmPciBase (0,SA_MC_DEV,SA_MC_FUN) + R_SA_REMAPBASE);

  if ((RemapBase & B_SA_REMAPBASE_LOCK_MASK) == 0) {
    DEBUG ((DEBUG_INFO, "Fail: REMAPBASE lock not set\n"));

    HstiErrorString = BuildHstiErrorString (HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_CODE_1 ,HSTI_MEMORY_MAP_SECURITY_CONFIGURATION, HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_STRING_1);
    Status = HstiLibAppendErrorString (
               PLATFORM_SECURITY_ROLE_PLATFORM_REFERENCE,
               NULL,
               HstiErrorString
               );
    ASSERT_EFI_ERROR (Status);
    Result = FALSE;
    FreePool (HstiErrorString);
  }

  DEBUG ((DEBUG_INFO, "    4. REMAPLIMIT\n"));
  RemapLimit = MmioRead64 (MmPciBase (0,SA_MC_DEV,SA_MC_FUN) + R_SA_REMAPLIMIT);

  if ((RemapLimit & B_SA_REMAPLIMIT_LOCK_MASK) == 0) {
    DEBUG ((DEBUG_INFO, "Fail: REMAPLIMIT lock not set\n"));

    HstiErrorString = BuildHstiErrorString (HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_CODE_1 ,HSTI_MEMORY_MAP_SECURITY_CONFIGURATION, HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_STRING_1);
    Status = HstiLibAppendErrorString (
               PLATFORM_SECURITY_ROLE_PLATFORM_REFERENCE,
               NULL,
               HstiErrorString
               );
    ASSERT_EFI_ERROR (Status);
    Result = FALSE;
    FreePool (HstiErrorString);
  }

  DEBUG ((DEBUG_INFO, "    5. Top Of Memory (TOM)\n"));
  Tom = MmioRead32 (MmPciBase (0,SA_MC_DEV,SA_MC_FUN) + R_SA_TOM);

  if ((Tom & B_SA_TOM_LOCK_MASK) == 0) {
    DEBUG ((DEBUG_INFO, "Fail: TOM lock not set\n"));

    HstiErrorString = BuildHstiErrorString (HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_CODE_1 ,HSTI_MEMORY_MAP_SECURITY_CONFIGURATION, HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_STRING_1);
    Status = HstiLibAppendErrorString (
               PLATFORM_SECURITY_ROLE_PLATFORM_REFERENCE,
               NULL,
               HstiErrorString
               );
    ASSERT_EFI_ERROR (Status);
    Result = FALSE;
    FreePool (HstiErrorString);
  }

  DEBUG ((DEBUG_INFO, "    6. Top Of Upper Usable DRAM (TOUUD)\n"));
  Touud = MmioRead32 (MmPciBase (0,SA_MC_DEV,SA_MC_FUN) + R_SA_TOUUD);

  if ((Touud & B_SA_TOUUD_LOCK_MASK) == 0) {
    DEBUG ((DEBUG_INFO, "Fail: TOUUD lock not set\n"));

    HstiErrorString = BuildHstiErrorString (HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_CODE_1 ,HSTI_MEMORY_MAP_SECURITY_CONFIGURATION, HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_STRING_1);
    Status = HstiLibAppendErrorString (
               PLATFORM_SECURITY_ROLE_PLATFORM_REFERENCE,
               NULL,
               HstiErrorString
               );
    ASSERT_EFI_ERROR (Status);
    Result = FALSE;
    FreePool (HstiErrorString);
  }

  DEBUG ((DEBUG_INFO, "    7. Top Of Lower Usable Memory (TOLUD)\n"));
  Tolud =MmioRead32 (MmPciBase (0,SA_MC_DEV,SA_MC_FUN) + R_SA_TOLUD);

  if ((Touud & B_SA_TOLUD_LOCK_MASK) == 0) {
    DEBUG ((DEBUG_INFO, "Fail: TOLUD lock not set\n"));

    HstiErrorString = BuildHstiErrorString (HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_CODE_1 ,HSTI_MEMORY_MAP_SECURITY_CONFIGURATION, HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_STRING_1);
    Status = HstiLibAppendErrorString (
               PLATFORM_SECURITY_ROLE_PLATFORM_REFERENCE,
               NULL,
               HstiErrorString
               );
    ASSERT_EFI_ERROR (Status);
    Result = FALSE;
    FreePool (HstiErrorString);
  }

  DEBUG ((DEBUG_INFO, "    8. Lockable/fixed memory ranges overlap\n"));

 //
 // Locate BIOS region size to update High bios base address
 //
    GetRegionAddress (&gFlashRegionBiosGuid, &BaseAddress, &RegionSize);
    DEBUG ((DEBUG_INFO, "Bios Region Size %x:\n", RegionSize));
    mLockableMemoryRange[LockableMemoryRangeHighBios].Base  = SIZE_4GB - RegionSize;
    mLockableMemoryRange[LockableMemoryRangeLowDram].End  = (MmioRead32 (MmPciBase (0,SA_MC_DEV,SA_MC_FUN) + R_SA_TOLUD) & B_SA_TOLUD_TOLUD_MASK) - 1;

  mLockableMemoryRange[LockableMemoryRangeHighDram].End = (MmioRead64 (MmPciBase (0,SA_MC_DEV,SA_MC_FUN) + R_SA_TOUUD) & B_SA_TOUUD_TOUUD_MASK) - 1;

  mLockableMemoryRange[LockableMemoryRangeMchBar].Base = MmioRead64 (MmPciBase (0,SA_MC_DEV,SA_MC_FUN) + R_SA_MCHBAR) & B_SA_MCHBAR_MCHBAR_MASK;
  mLockableMemoryRange[LockableMemoryRangeMchBar].End  = mLockableMemoryRange[LockableMemoryRangeMchBar].Base + SIZE_32KB - 1;

  mLockableMemoryRange[LockableMemoryRangeDmiBar].Base = MmioRead64 (MmPciBase (0,SA_MC_DEV,SA_MC_FUN) + R_SA_DMIBAR) & B_SA_DMIBAR_DMIBAR_MASK;
  mLockableMemoryRange[LockableMemoryRangeDmiBar].End  = mLockableMemoryRange[LockableMemoryRangeDmiBar].Base + SIZE_4KB - 1;
  mLockableMemoryRange[LockableMemoryRangePxpEpBar].Base = MmioRead64 (MmPciBase (0,SA_MC_DEV,SA_MC_FUN) + R_SA_PXPEPBAR) & B_SA_PXPEPBAR_PXPEPBAR_MASK;
  mLockableMemoryRange[LockableMemoryRangePxpEpBar].End  = mLockableMemoryRange[LockableMemoryRangePxpEpBar].Base + SIZE_4KB - 1;
  Data64 = MmioRead64 (MchBar + 0x5400);
  if ((Data64 & BIT0) != 0) {
    mLockableMemoryRange[LockableMemoryRangeGfxVtBar].Base = Data64 & 0x7FFFFFF000;
    mLockableMemoryRange[LockableMemoryRangeGfxVtBar].End  = mLockableMemoryRange[LockableMemoryRangeGfxVtBar].Base + 0x1000 - 1;
  }
  Data64 = MmioRead64 (MchBar + 0x5410);
  if ((Data64 & BIT0) != 0) {
    mLockableMemoryRange[LockableMemoryRangeVtdPvc0Bar].Base = Data64 & 0x7FFFFFF000;
    mLockableMemoryRange[LockableMemoryRangeVtdPvc0Bar].End  = mLockableMemoryRange[LockableMemoryRangeVtdPvc0Bar].Base + 0x1000 - 1;
  }
  Data64 = MmioRead64 (MchBar + 0x5420);
  if ((Data64 & BIT0) != 0) {
    mLockableMemoryRange[LockableMemoryRangeGdxcBar].Base = Data64 & 0x7FFFFFF000;
    mLockableMemoryRange[LockableMemoryRangeGdxcBar].End  = mLockableMemoryRange[LockableMemoryRangeGdxcBar].Base + 0x1000 - 1;
  }
  Data64 = MmioRead64 (MchBar + 0x5408);
  if ((Data64 & BIT0) != 0) {
    mLockableMemoryRange[LockableMemoryRangeEdramBar].Base = Data64 & 0x7FFFFFC000;
    mLockableMemoryRange[LockableMemoryRangeEdramBar].End  = mLockableMemoryRange[LockableMemoryRangeEdramBar].Base + 0x4000 - 1;
  }

  DEBUG ((DEBUG_INFO, "Lockable memory ranges:\n"));
  DumpRange (mLockableMemoryRange, LockableMemoryRangeMax);
  if (CheckOverlap (mLockableMemoryRange, LockableMemoryRangeMax) || EFI_ERROR (Status)) {

    HstiErrorString = BuildHstiErrorString (HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_CODE_2 ,HSTI_MEMORY_MAP_SECURITY_CONFIGURATION, HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_STRING_2);
    Status = HstiLibAppendErrorString (
               PLATFORM_SECURITY_ROLE_PLATFORM_REFERENCE,
               NULL,
               HstiErrorString
               );
    ASSERT_EFI_ERROR (Status);
    Result = FALSE;
    FreePool (HstiErrorString);
  }

  DEBUG ((DEBUG_INFO, "    9. Non lockable memory ranges overlap\n"));

  if (MmioRead32 (MmPciBase (0,0,0) + 0x54) & BIT3) {
    mNonLockableMemoryRange[NonLockableMemoryRangeMBASE0].Base = LShiftU64 ((MmioRead16 (MmPciBase (0,SA_PEG10_DEV_NUM,SA_PEG10_FUN_NUM) + 0x20) & 0xFFF0),16);
    mNonLockableMemoryRange[NonLockableMemoryRangeMBASE0].End  = LShiftU64 ((MmioRead16 (MmPciBase (0,SA_PEG10_DEV_NUM,SA_PEG10_FUN_NUM) + 0x22) & 0xFFF0),16);

    BarRead = MmioRead16 (MmPciBase (0,SA_PEG10_DEV_NUM,SA_PEG10_FUN_NUM) + 0x24);
    if ((BarRead & 0xF) != 0) {
      mNonLockableMemoryRange[NonLockableMemoryRangePMBASE0].Base = LShiftU64 ((BarRead & 0xFFF0),16) + LShiftU64 ((MmioRead32 (MmPciBase (0,SA_PEG10_DEV_NUM,SA_PEG10_FUN_NUM) + 0x28)),32);
    } else {
      mNonLockableMemoryRange[NonLockableMemoryRangePMBASE0].Base = LShiftU64 ((BarRead & 0xFFF0),16);
    }

    BarRead = MmioRead16 (MmPciBase (0,SA_PEG10_DEV_NUM,SA_PEG10_FUN_NUM) + 0x26);
    if ((BarRead & 0xF) != 0) {
      mNonLockableMemoryRange[NonLockableMemoryRangePMBASE0].End = LShiftU64 ((BarRead & 0xFFF0),16) + LShiftU64 ((MmioRead32 (MmPciBase (0,SA_PEG10_DEV_NUM,SA_PEG10_FUN_NUM) + 0x2C)),32);
    } else {
      mNonLockableMemoryRange[NonLockableMemoryRangePMBASE0].End = LShiftU64 ((BarRead & 0xFFF0),16);
    }
  }

  //
  // Check to make sure that if PEG0 is enabled but nothing is connected that we ignore these ranges
  //
  if(mNonLockableMemoryRange[NonLockableMemoryRangeMBASE0].End < mNonLockableMemoryRange[NonLockableMemoryRangeMBASE0].Base)
  {
    mNonLockableMemoryRange[NonLockableMemoryRangeMBASE0].Base = 0;
    mNonLockableMemoryRange[NonLockableMemoryRangeMBASE0].End  = 0;
  }
  if(mNonLockableMemoryRange[NonLockableMemoryRangePMBASE0].End < mNonLockableMemoryRange[NonLockableMemoryRangePMBASE0].Base)
  {
    mNonLockableMemoryRange[NonLockableMemoryRangePMBASE0].Base = 0;
    mNonLockableMemoryRange[NonLockableMemoryRangePMBASE0].End  = 0;
  }

  if (MmioRead32 (MmPciBase (0,0,0) + 0x54) & BIT2) {
    mNonLockableMemoryRange[NonLockableMemoryRangeMBASE1].Base = LShiftU64 ((MmioRead16 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_PEG11_DEV_NUM,SA_PEG11_FUN_NUM) + 0x20) & 0xFFF0),16);
    mNonLockableMemoryRange[NonLockableMemoryRangeMBASE1].End  = LShiftU64 ((MmioRead16 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_PEG11_DEV_NUM,SA_PEG11_FUN_NUM) + 0x22) & 0xFFF0),16);

    BarRead = MmioRead16 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_PEG11_DEV_NUM,SA_PEG11_FUN_NUM) + 0x24);

    if ((BarRead & 0xF) != 0) {
      mNonLockableMemoryRange[NonLockableMemoryRangePMBASE1].Base = LShiftU64 ((BarRead & 0xFFF0),16) + LShiftU64 ((MmioRead16 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_PEG11_DEV_NUM,SA_PEG11_FUN_NUM) + 0x28)),32);
    } else {
      mNonLockableMemoryRange[NonLockableMemoryRangePMBASE1].Base = LShiftU64 ((BarRead & 0xFFF0),16);
    }

    BarRead = MmioRead16 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_PEG11_DEV_NUM,SA_PEG11_FUN_NUM) + 0x26);
    if ((BarRead & 0xF) != 0) {
      mNonLockableMemoryRange[NonLockableMemoryRangePMBASE1].End = LShiftU64 ((BarRead & 0xFFF0),16) + LShiftU64 ((MmioRead16 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_PEG11_DEV_NUM,SA_PEG11_FUN_NUM) + 0x2C)),32);
    } else {
      mNonLockableMemoryRange[NonLockableMemoryRangePMBASE1].End = LShiftU64 ((BarRead & 0xFFF0),16);
    }
  }

  //
  // Check to make sure that if PEG1 is enabled but nothing is connected that we ignore these ranges
  //
  if(mNonLockableMemoryRange[NonLockableMemoryRangeMBASE1].End < mNonLockableMemoryRange[NonLockableMemoryRangeMBASE1].Base)
  {
    mNonLockableMemoryRange[NonLockableMemoryRangeMBASE1].Base = 0;
    mNonLockableMemoryRange[NonLockableMemoryRangeMBASE1].End  = 0;
  }
  if(mNonLockableMemoryRange[NonLockableMemoryRangePMBASE1].End < mNonLockableMemoryRange[NonLockableMemoryRangePMBASE1].Base)
  {
    mNonLockableMemoryRange[NonLockableMemoryRangePMBASE1].Base = 0;
    mNonLockableMemoryRange[NonLockableMemoryRangePMBASE1].End  = 0;
  }

  if (MmioRead32 (MmPciBase (0,0,0) + 0x54) & BIT1) {
    mNonLockableMemoryRange[NonLockableMemoryRangeMBASE2].Base = LShiftU64 ((MmioRead16 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_PEG12_DEV_NUM,SA_PEG12_FUN_NUM) + 0x20) & 0xFFF0),16);
    mNonLockableMemoryRange[NonLockableMemoryRangeMBASE2].End  = LShiftU64 ((MmioRead16 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_PEG12_DEV_NUM,SA_PEG12_FUN_NUM) + 0x22) & 0xFFF0),16);

    BarRead = MmioRead16 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_PEG12_DEV_NUM,SA_PEG12_FUN_NUM) + 0x24);
    if ((BarRead & 0xF) != 0) {
      mNonLockableMemoryRange[NonLockableMemoryRangePMBASE2].Base = LShiftU64 ((BarRead & 0xFFF0),16) + LShiftU64 ((MmioRead16 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_PEG12_DEV_NUM,SA_PEG12_FUN_NUM) + 0x28)),32);

    } else {
      mNonLockableMemoryRange[NonLockableMemoryRangePMBASE2].Base = LShiftU64 ((BarRead & 0xFFF0),16);
    }

    BarRead = MmioRead16 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_PEG12_DEV_NUM,SA_PEG12_FUN_NUM) + 0x26);

    if ((BarRead & 0xF) != 0) {
      mNonLockableMemoryRange[NonLockableMemoryRangePMBASE2].End = LShiftU64 ((BarRead & 0xFFF0),16) + LShiftU64 ((MmioRead16 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_PEG12_DEV_NUM,SA_PEG12_FUN_NUM) + 0x2C)),32);
    } else {
      mNonLockableMemoryRange[NonLockableMemoryRangePMBASE2].End = LShiftU64 ((BarRead & 0xFFF0),16);
    }
  }

  //
  // Check to make sure that if PEG2 is enabled but nothing is connected that we ignore these ranges
  //
  if(mNonLockableMemoryRange[NonLockableMemoryRangeMBASE2].End < mNonLockableMemoryRange[NonLockableMemoryRangeMBASE2].Base)
  {
    mNonLockableMemoryRange[NonLockableMemoryRangeMBASE2].Base = 0;
    mNonLockableMemoryRange[NonLockableMemoryRangeMBASE2].End = 0;
  }
  if(mNonLockableMemoryRange[NonLockableMemoryRangePMBASE2].End < mNonLockableMemoryRange[NonLockableMemoryRangePMBASE2].Base)
  {
    mNonLockableMemoryRange[NonLockableMemoryRangePMBASE2].Base = 0;
    mNonLockableMemoryRange[NonLockableMemoryRangePMBASE2].End  = 0;
  }

  if (MmioRead32 (MmPciBase (0,0,0) + 0x54) & BIT4) {
    mNonLockableMemoryRange[NonLockableMemoryRangeGTTMMADR].Base = (LShiftU64 (MmioRead32 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_IGD_DEV,SA_IGD_FUN_0) + R_SA_IGD_GTTMMADR + 4), 32) + \
                                                                     (MmioRead32 (MmPciBase(DEFAULT_PCI_BUS_NUMBER_PCH,SA_IGD_DEV,SA_IGD_FUN_0) + R_SA_IGD_GTTMMADR))) & 0x7FFF000000;
    mNonLockableMemoryRange[NonLockableMemoryRangeGTTMMADR].End  = mNonLockableMemoryRange[NonLockableMemoryRangeGTTMMADR].Base + SIZE_16MB - 1;

    Msac = MmioRead8 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_IGD_DEV,SA_MC_FUN) + R_SA_IGD_MSAC_OFFSET);
    ApertureSize = ((Msac & (BIT0 | BIT1 | BIT2 | BIT3 | BIT4)) + 1) * SIZE_128MB;
    mNonLockableMemoryRange[NonLockableMemoryRangeGMADR].Base    = (LShiftU64 (MmioRead32 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,SA_IGD_DEV,SA_IGD_FUN_0) + R_SA_IGD_GMADR + 4), 32) + \
                                                                     (MmioRead32 (MmPciBase(DEFAULT_PCI_BUS_NUMBER_PCH,SA_IGD_DEV,SA_IGD_FUN_0) + R_SA_IGD_GMADR))) & 0x7FF8000000;
    mNonLockableMemoryRange[NonLockableMemoryRangeGMADR].End     = mNonLockableMemoryRange[NonLockableMemoryRangeGMADR].Base + ApertureSize - 1;
  }

  if (MmioRead32 (MmPciBase (0,0,0) + 0x54) & BIT7) {
    mNonLockableMemoryRange[NonLockableMemoryRangeTMBAR].Base = MmioRead64 (MmPciBase (0,4,0) + 0x10) & 0x7FFFFF8000;
    mNonLockableMemoryRange[NonLockableMemoryRangeTMBAR].End  =   mNonLockableMemoryRange[NonLockableMemoryRangeTMBAR].Base + SIZE_32KB-1;
  }

  VendorIdRead = MmioRead16 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,PCI_DEVICE_NUMBER_PCH_SATA,PCI_FUNCTION_NUMBER_PCH_SATA) +0);
  DEBUG ((DEBUG_INFO, "VendorIdRead SATA: %x\n",VendorIdRead));

  if (VendorIdRead != 0xFFFF) {
    BarRead = MmioRead32 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,PCI_DEVICE_NUMBER_PCH_SATA,PCI_FUNCTION_NUMBER_PCH_SATA) + R_PCH_SATA_SATAGC);

    if ((BarRead & BIT10) == 0 ) {
      mNonLockableMemoryRange[NonLockableMemoryRangeABAR].Base = MmioRead32 (MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH,PCI_DEVICE_NUMBER_PCH_SATA,PCI_FUNCTION_NUMBER_PCH_SATA) + R_PCH_SATA_AHCI_BAR) & 0xFFFFF800;

      switch (BarRead & 0x7) {
        case V_PCH_SATA_SATAGC_ASSEL_2K:
          AbarSize = SIZE_2KB;
          break;

        case V_PCH_SATA_SATAGC_ASSEL_16K:
          AbarSize = SIZE_16KB;
          break;

        case V_PCH_SATA_SATAGC_ASSEL_32K:
          AbarSize = SIZE_32KB;
          break;

        case V_PCH_SATA_SATAGC_ASSEL_64K:
          AbarSize = SIZE_64KB;
          break;

        case V_PCH_SATA_SATAGC_ASSEL_128K:
          AbarSize = SIZE_128KB;
          break;

        case V_PCH_SATA_SATAGC_ASSEL_512K:
          AbarSize = SIZE_256KB;
          break;

        default:
          AbarSize= SIZE_2KB;
          break;
      }
      mNonLockableMemoryRange[NonLockableMemoryRangeABAR].End  = mNonLockableMemoryRange[NonLockableMemoryRangeABAR].Base + AbarSize - 1;
    }
  }

  mNonLockableMemoryRange[NonLockableMemoryRangeSBREG_BAR].Base = PCH_PCR_BASE_ADDRESS;
  mNonLockableMemoryRange[NonLockableMemoryRangeSBREG_BAR].End = PCH_PCR_BASE_ADDRESS + SIZE_16MB-1;

  PchPwrmBaseGet (&PwrmBase);
  mNonLockableMemoryRange[NonLockableMemoryRangePWRMBASE].Base = PwrmBase;
  mNonLockableMemoryRange[NonLockableMemoryRangePWRMBASE].End  = PwrmBase + PCH_PWRM_MMIO_SIZE - 1;

  PchSpiBase = MmioRead32 (MmPciBase (
                             DEFAULT_PCI_BUS_NUMBER_PCH,
                             PCI_DEVICE_NUMBER_PCH_SPI,
                             PCI_FUNCTION_NUMBER_PCH_SPI)
                             + R_PCH_SPI_BAR0) & ~B_PCH_SPI_BAR0_MASK;

  mNonLockableMemoryRange[NonLockableMemoryRangeSPI_BAR0].Base = PchSpiBase;
  mNonLockableMemoryRange[NonLockableMemoryRangeSPI_BAR0].End  = PchSpiBase + SIZE_4KB-1;

  DEBUG ((DEBUG_INFO, "Non lockable memory ranges:\n"));
  DumpRange (mNonLockableMemoryRange, NonLockableMemoryRangeMax);
  if (CheckOverlap (mNonLockableMemoryRange, NonLockableMemoryRangeMax) ||
      CheckOverlap2 (mLockableMemoryRange, LockableMemoryRangeMax, mNonLockableMemoryRange, NonLockableMemoryRangeMax)) {

    HstiErrorString = BuildHstiErrorString (HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_CODE_3 ,HSTI_MEMORY_MAP_SECURITY_CONFIGURATION, HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION_ERROR_STRING_3);
    Status = HstiLibAppendErrorString (
               PLATFORM_SECURITY_ROLE_PLATFORM_REFERENCE,
               NULL,
               HstiErrorString
               );
    ASSERT_EFI_ERROR (Status);
    Result = FALSE;
    FreePool (HstiErrorString);
  }

  //
  // ALL PASS
  //
  if (Result) {
    Status = HstiLibSetFeaturesVerified (
               PLATFORM_SECURITY_ROLE_PLATFORM_REFERENCE,
               NULL,
               1,
               HSTI_BYTE1_SECURE_MEMORY_MAP_CONFIGURATION
               );
    ASSERT_EFI_ERROR (Status);
  }

  return;
}
