The unit test app supports running in 3 mode:
1. MtrrLibUnitTest generate-random-numbers
     <path to MtrrLib/UnitTest/RandomNumber.c> <random-number count>
   It generates random numbers and writes to RandomNumber.c.
2. MtrrLibUnitTest [<iterations>]
   It tests MtrrLib APIs using configurations generated from static
   numbers generated by mode #1.
   This is the default execution mode running in CI environment.
3. MtrrLibUnitTest <iterations> random
   It tests MtrrLib APIs using configurations generated from random
   numbers.
   This is what developers can use to test MtrrLib for regressions.
Signed-off-by: Ray Ni <ray.ni@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ming Shao <ming.shao@intel.com>
Cc: Sean Brogan <sean.brogan@microsoft.com>
Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
		
	
		
			
				
	
	
		
			988 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			988 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Unit tests of the MtrrLib instance of the MtrrLib class
 | 
						|
 | 
						|
  Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "MtrrLibUnitTest.h"
 | 
						|
 | 
						|
MTRR_MEMORY_CACHE_TYPE mMemoryCacheTypes[] = {
 | 
						|
  CacheUncacheable, CacheWriteCombining, CacheWriteThrough, CacheWriteProtected, CacheWriteBack
 | 
						|
  };
 | 
						|
 | 
						|
UINT64                           mFixedMtrrsValue[MTRR_NUMBER_OF_FIXED_MTRR];
 | 
						|
MSR_IA32_MTRR_PHYSBASE_REGISTER  mVariableMtrrsPhysBase[MTRR_NUMBER_OF_VARIABLE_MTRR];
 | 
						|
MSR_IA32_MTRR_PHYSMASK_REGISTER  mVariableMtrrsPhysMask[MTRR_NUMBER_OF_VARIABLE_MTRR];
 | 
						|
MSR_IA32_MTRR_DEF_TYPE_REGISTER  mDefTypeMsr;
 | 
						|
MSR_IA32_MTRRCAP_REGISTER        mMtrrCapMsr;
 | 
						|
CPUID_VERSION_INFO_EDX           mCpuidVersionInfoEdx;
 | 
						|
CPUID_VIR_PHY_ADDRESS_SIZE_EAX   mCpuidVirPhyAddressSizeEax;
 | 
						|
 | 
						|
BOOLEAN                          mRandomInput;
 | 
						|
UINTN                            mNumberIndex = 0;
 | 
						|
extern UINTN                     mNumbers[];
 | 
						|
extern UINTN                     mNumberCount;
 | 
						|
 | 
						|
/**
 | 
						|
  Return a random number between 0 and RAND_MAX.
 | 
						|
 | 
						|
  If mRandomInput is TRUE, the routine directly calls rand().
 | 
						|
  Otherwise, the routine returns the pre-generated numbers.
 | 
						|
 | 
						|
  @return a number between 0 and RAND_MAX.
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
Rand (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (mRandomInput) {
 | 
						|
    return rand ();
 | 
						|
  } else {
 | 
						|
    DEBUG ((DEBUG_INFO, "random: %d\n", mNumberIndex));
 | 
						|
    return mNumbers[mNumberIndex++ % (mNumberCount - 1)];
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
CHAR8  mContentTemplate[] = {
 | 
						|
  "/** @file\n"
 | 
						|
  "  Pre-generated random number used by MtrrLib test.\n"
 | 
						|
  "\n"
 | 
						|
  "  Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\n"
 | 
						|
  "  SPDX-License-Identifier: BSD-2-Clause-Patent\n"
 | 
						|
  "**/\n"
 | 
						|
  "UINTN mNumberCount = %d;\n"
 | 
						|
  "UINTN mNumbers[] = {"
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Generate Count random numbers in FilePath.
 | 
						|
 | 
						|
  @param FilePath  The file path to put the generated random numbers.
 | 
						|
  @param Count     Count of random numbers.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
GenerateRandomNumbers (
 | 
						|
  CHAR8         *FilePath,
 | 
						|
  UINTN         Count
 | 
						|
  )
 | 
						|
{
 | 
						|
  FILE   *File;
 | 
						|
  UINTN  Index;
 | 
						|
 | 
						|
  File = fopen (FilePath, "w");
 | 
						|
  fprintf (File, mContentTemplate, Count);
 | 
						|
  for (Index = 0; Index < Count; Index++) {
 | 
						|
    if (Index % 10 == 0) {
 | 
						|
      fprintf (File, "\n ");
 | 
						|
    }
 | 
						|
    fprintf (File, " %d,", rand ());
 | 
						|
  }
 | 
						|
  fprintf (File, "\n};\n");
 | 
						|
  fclose (File);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieves CPUID information.
 | 
						|
 | 
						|
  Executes the CPUID instruction with EAX set to the value specified by Index.
 | 
						|
  This function always returns Index.
 | 
						|
  If Eax is not NULL, then the value of EAX after CPUID is returned in Eax.
 | 
						|
  If Ebx is not NULL, then the value of EBX after CPUID is returned in Ebx.
 | 
						|
  If Ecx is not NULL, then the value of ECX after CPUID is returned in Ecx.
 | 
						|
  If Edx is not NULL, then the value of EDX after CPUID is returned in Edx.
 | 
						|
  This function is only available on IA-32 and x64.
 | 
						|
 | 
						|
  @param  Index The 32-bit value to load into EAX prior to invoking the CPUID
 | 
						|
                instruction.
 | 
						|
  @param  Eax   The pointer to the 32-bit EAX value returned by the CPUID
 | 
						|
                instruction. This is an optional parameter that may be NULL.
 | 
						|
  @param  Ebx   The pointer to the 32-bit EBX value returned by the CPUID
 | 
						|
                instruction. This is an optional parameter that may be NULL.
 | 
						|
  @param  Ecx   The pointer to the 32-bit ECX value returned by the CPUID
 | 
						|
                instruction. This is an optional parameter that may be NULL.
 | 
						|
  @param  Edx   The pointer to the 32-bit EDX value returned by the CPUID
 | 
						|
                instruction. This is an optional parameter that may be NULL.
 | 
						|
 | 
						|
  @return Index.
 | 
						|
 | 
						|
**/
 | 
						|
UINT32
 | 
						|
EFIAPI
 | 
						|
UnitTestMtrrLibAsmCpuid (
 | 
						|
  IN      UINT32                    Index,
 | 
						|
  OUT     UINT32                    *Eax,  OPTIONAL
 | 
						|
  OUT     UINT32                    *Ebx,  OPTIONAL
 | 
						|
  OUT     UINT32                    *Ecx,  OPTIONAL
 | 
						|
  OUT     UINT32                    *Edx   OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  switch (Index) {
 | 
						|
  case CPUID_VERSION_INFO:
 | 
						|
    if (Edx != NULL) {
 | 
						|
      *Edx = mCpuidVersionInfoEdx.Uint32;
 | 
						|
    }
 | 
						|
    return Index;
 | 
						|
    break;
 | 
						|
  case CPUID_EXTENDED_FUNCTION:
 | 
						|
    if (Eax != NULL) {
 | 
						|
      *Eax = CPUID_VIR_PHY_ADDRESS_SIZE;
 | 
						|
    }
 | 
						|
    return Index;
 | 
						|
    break;
 | 
						|
  case CPUID_VIR_PHY_ADDRESS_SIZE:
 | 
						|
    if (Eax != NULL) {
 | 
						|
      *Eax = mCpuidVirPhyAddressSizeEax.Uint32;
 | 
						|
    }
 | 
						|
    return Index;
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Should never fall through to here
 | 
						|
  //
 | 
						|
  ASSERT(FALSE);
 | 
						|
  return Index;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Returns a 64-bit Machine Specific Register(MSR).
 | 
						|
 | 
						|
  Reads and returns the 64-bit MSR specified by Index. No parameter checking is
 | 
						|
  performed on Index, and some Index values may cause CPU exceptions. The
 | 
						|
  caller must either guarantee that Index is valid, or the caller must set up
 | 
						|
  exception handlers to catch the exceptions. This function is only available
 | 
						|
  on IA-32 and x64.
 | 
						|
 | 
						|
  @param  MsrIndex The 32-bit MSR index to read.
 | 
						|
 | 
						|
  @return The value of the MSR identified by MsrIndex.
 | 
						|
 | 
						|
**/
 | 
						|
UINT64
 | 
						|
EFIAPI
 | 
						|
UnitTestMtrrLibAsmReadMsr64(
 | 
						|
  IN UINT32  MsrIndex
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32 Index;
 | 
						|
 | 
						|
  for (Index = 0; Index < ARRAY_SIZE (mFixedMtrrsValue); Index++) {
 | 
						|
    if (MsrIndex == mFixedMtrrsIndex[Index]) {
 | 
						|
      return mFixedMtrrsValue[Index];
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if ((MsrIndex >= MSR_IA32_MTRR_PHYSBASE0) &&
 | 
						|
      (MsrIndex <= MSR_IA32_MTRR_PHYSMASK0 + (MTRR_NUMBER_OF_VARIABLE_MTRR << 1))) {
 | 
						|
    if (MsrIndex % 2 == 0) {
 | 
						|
      Index = (MsrIndex - MSR_IA32_MTRR_PHYSBASE0) >> 1;
 | 
						|
      return mVariableMtrrsPhysBase[Index].Uint64;
 | 
						|
    } else {
 | 
						|
      Index = (MsrIndex - MSR_IA32_MTRR_PHYSMASK0) >> 1;
 | 
						|
      return mVariableMtrrsPhysMask[Index].Uint64;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (MsrIndex == MSR_IA32_MTRR_DEF_TYPE) {
 | 
						|
    return mDefTypeMsr.Uint64;
 | 
						|
  }
 | 
						|
 | 
						|
  if (MsrIndex == MSR_IA32_MTRRCAP) {
 | 
						|
    return mMtrrCapMsr.Uint64;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Should never fall through to here
 | 
						|
  //
 | 
						|
  ASSERT(FALSE);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Writes a 64-bit value to a Machine Specific Register(MSR), and returns the
 | 
						|
  value.
 | 
						|
 | 
						|
  Writes the 64-bit value specified by Value to the MSR specified by Index. The
 | 
						|
  64-bit value written to the MSR is returned. No parameter checking is
 | 
						|
  performed on Index or Value, and some of these may cause CPU exceptions. The
 | 
						|
  caller must either guarantee that Index and Value are valid, or the caller
 | 
						|
  must establish proper exception handlers. This function is only available on
 | 
						|
  IA-32 and x64.
 | 
						|
 | 
						|
  @param  MsrIndex The 32-bit MSR index to write.
 | 
						|
  @param  Value The 64-bit value to write to the MSR.
 | 
						|
 | 
						|
  @return Value
 | 
						|
 | 
						|
**/
 | 
						|
UINT64
 | 
						|
EFIAPI
 | 
						|
UnitTestMtrrLibAsmWriteMsr64(
 | 
						|
  IN      UINT32                    MsrIndex,
 | 
						|
  IN      UINT64                    Value
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32 Index;
 | 
						|
 | 
						|
  for (Index = 0; Index < ARRAY_SIZE (mFixedMtrrsValue); Index++) {
 | 
						|
    if (MsrIndex == mFixedMtrrsIndex[Index]) {
 | 
						|
      mFixedMtrrsValue[Index] = Value;
 | 
						|
      return Value;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if ((MsrIndex >= MSR_IA32_MTRR_PHYSBASE0) &&
 | 
						|
      (MsrIndex <= MSR_IA32_MTRR_PHYSMASK0 + (MTRR_NUMBER_OF_VARIABLE_MTRR << 1))) {
 | 
						|
    if (MsrIndex % 2 == 0) {
 | 
						|
      Index = (MsrIndex - MSR_IA32_MTRR_PHYSBASE0) >> 1;
 | 
						|
      mVariableMtrrsPhysBase[Index].Uint64 = Value;
 | 
						|
      return Value;
 | 
						|
    } else {
 | 
						|
      Index = (MsrIndex - MSR_IA32_MTRR_PHYSMASK0) >> 1;
 | 
						|
      mVariableMtrrsPhysMask[Index].Uint64 = Value;
 | 
						|
      return Value;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (MsrIndex == MSR_IA32_MTRR_DEF_TYPE) {
 | 
						|
    mDefTypeMsr.Uint64 = Value;
 | 
						|
    return Value;
 | 
						|
  }
 | 
						|
 | 
						|
  if (MsrIndex == MSR_IA32_MTRRCAP) {
 | 
						|
    mMtrrCapMsr.Uint64 = Value;
 | 
						|
    return Value;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Should never fall through to here
 | 
						|
  //
 | 
						|
  ASSERT(FALSE);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize the MTRR registers.
 | 
						|
 | 
						|
  @param SystemParameter System parameter that controls the MTRR registers initialization.
 | 
						|
**/
 | 
						|
UNIT_TEST_STATUS
 | 
						|
EFIAPI
 | 
						|
InitializeMtrrRegs (
 | 
						|
  IN MTRR_LIB_SYSTEM_PARAMETER  *SystemParameter
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32                    Index;
 | 
						|
 | 
						|
  SetMem (mFixedMtrrsValue, sizeof (mFixedMtrrsValue), SystemParameter->DefaultCacheType);
 | 
						|
 | 
						|
  for (Index = 0; Index < ARRAY_SIZE (mVariableMtrrsPhysBase); Index++) {
 | 
						|
    mVariableMtrrsPhysBase[Index].Uint64         = 0;
 | 
						|
    mVariableMtrrsPhysBase[Index].Bits.Type      = SystemParameter->DefaultCacheType;
 | 
						|
    mVariableMtrrsPhysBase[Index].Bits.Reserved1 = 0;
 | 
						|
 | 
						|
    mVariableMtrrsPhysMask[Index].Uint64         = 0;
 | 
						|
    mVariableMtrrsPhysMask[Index].Bits.V         = 0;
 | 
						|
    mVariableMtrrsPhysMask[Index].Bits.Reserved1 = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  mDefTypeMsr.Bits.E         = 1;
 | 
						|
  mDefTypeMsr.Bits.FE        = 1;
 | 
						|
  mDefTypeMsr.Bits.Type      = SystemParameter->DefaultCacheType;
 | 
						|
  mDefTypeMsr.Bits.Reserved1 = 0;
 | 
						|
  mDefTypeMsr.Bits.Reserved2 = 0;
 | 
						|
  mDefTypeMsr.Bits.Reserved3 = 0;
 | 
						|
 | 
						|
  mMtrrCapMsr.Bits.SMRR      = 0;
 | 
						|
  mMtrrCapMsr.Bits.WC        = 0;
 | 
						|
  mMtrrCapMsr.Bits.VCNT      = SystemParameter->VariableMtrrCount;
 | 
						|
  mMtrrCapMsr.Bits.FIX       = SystemParameter->FixedMtrrSupported;
 | 
						|
  mMtrrCapMsr.Bits.Reserved1 = 0;
 | 
						|
  mMtrrCapMsr.Bits.Reserved2 = 0;
 | 
						|
  mMtrrCapMsr.Bits.Reserved3 = 0;
 | 
						|
 | 
						|
  mCpuidVersionInfoEdx.Bits.MTRR                      = SystemParameter->MtrrSupported;
 | 
						|
  mCpuidVirPhyAddressSizeEax.Bits.PhysicalAddressBits = SystemParameter->PhysicalAddressBits;
 | 
						|
 | 
						|
  //
 | 
						|
  // Hook BaseLib functions used by MtrrLib that require some emulation.
 | 
						|
  //
 | 
						|
  gUnitTestHostBaseLib.X86->AsmCpuid      = UnitTestMtrrLibAsmCpuid;
 | 
						|
  gUnitTestHostBaseLib.X86->AsmReadMsr64  = UnitTestMtrrLibAsmReadMsr64;
 | 
						|
  gUnitTestHostBaseLib.X86->AsmWriteMsr64 = UnitTestMtrrLibAsmWriteMsr64;
 | 
						|
 | 
						|
  return UNIT_TEST_PASSED;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize the MTRR registers.
 | 
						|
 | 
						|
  @param Context System parameter that controls the MTRR registers initialization.
 | 
						|
**/
 | 
						|
UNIT_TEST_STATUS
 | 
						|
EFIAPI
 | 
						|
InitializeSystem (
 | 
						|
  IN UNIT_TEST_CONTEXT        Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  return InitializeMtrrRegs ((MTRR_LIB_SYSTEM_PARAMETER *) Context);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Collect the test result.
 | 
						|
 | 
						|
  @param DefaultType          Default memory type.
 | 
						|
  @param PhysicalAddressBits  Physical address bits.
 | 
						|
  @param VariableMtrrCount    Count of variable MTRRs.
 | 
						|
  @param Mtrrs                MTRR settings to collect from.
 | 
						|
  @param Ranges               Return the memory ranges.
 | 
						|
  @param RangeCount           Return the count of memory ranges.
 | 
						|
  @param MtrrCount            Return the count of variable MTRRs being used.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
CollectTestResult (
 | 
						|
  IN     MTRR_MEMORY_CACHE_TYPE DefaultType,
 | 
						|
  IN     UINT32                 PhysicalAddressBits,
 | 
						|
  IN     UINT32                 VariableMtrrCount,
 | 
						|
  IN     MTRR_SETTINGS          *Mtrrs,
 | 
						|
  OUT    MTRR_MEMORY_RANGE      *Ranges,
 | 
						|
  IN OUT UINTN                  *RangeCount,
 | 
						|
  OUT    UINT32                 *MtrrCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN             Index;
 | 
						|
  UINT64            MtrrValidBitsMask;
 | 
						|
  UINT64            MtrrValidAddressMask;
 | 
						|
  MTRR_MEMORY_RANGE RawMemoryRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)];
 | 
						|
 | 
						|
  ASSERT (Mtrrs != NULL);
 | 
						|
  ASSERT (VariableMtrrCount <= ARRAY_SIZE (Mtrrs->Variables.Mtrr));
 | 
						|
 | 
						|
  MtrrValidBitsMask = (1ull << PhysicalAddressBits) - 1;
 | 
						|
  MtrrValidAddressMask = MtrrValidBitsMask & ~0xFFFull;
 | 
						|
 | 
						|
  *MtrrCount = 0;
 | 
						|
  for (Index = 0; Index < VariableMtrrCount; Index++) {
 | 
						|
    if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &Mtrrs->Variables.Mtrr[Index].Mask)->Bits.V == 1) {
 | 
						|
      RawMemoryRanges[*MtrrCount].BaseAddress = Mtrrs->Variables.Mtrr[Index].Base & MtrrValidAddressMask;
 | 
						|
      RawMemoryRanges[*MtrrCount].Type        =
 | 
						|
        ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &Mtrrs->Variables.Mtrr[Index].Base)->Bits.Type;
 | 
						|
      RawMemoryRanges[*MtrrCount].Length      =
 | 
						|
          ((~(Mtrrs->Variables.Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;
 | 
						|
      (*MtrrCount)++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  GetEffectiveMemoryRanges (DefaultType, PhysicalAddressBits, RawMemoryRanges, *MtrrCount, Ranges, RangeCount);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return a 32bit random number.
 | 
						|
 | 
						|
  @param Start  Start of the random number range.
 | 
						|
  @param Limit  Limit of the random number range.
 | 
						|
  @return 32bit random number
 | 
						|
**/
 | 
						|
UINT32
 | 
						|
Random32 (
 | 
						|
  UINT32  Start,
 | 
						|
  UINT32  Limit
 | 
						|
  )
 | 
						|
{
 | 
						|
  return (UINT32) (((double) Rand () / RAND_MAX) * (Limit - Start)) + Start;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return a 64bit random number.
 | 
						|
 | 
						|
  @param Start  Start of the random number range.
 | 
						|
  @param Limit  Limit of the random number range.
 | 
						|
  @return 64bit random number
 | 
						|
**/
 | 
						|
UINT64
 | 
						|
Random64 (
 | 
						|
  UINT64  Start,
 | 
						|
  UINT64  Limit
 | 
						|
  )
 | 
						|
{
 | 
						|
  return (UINT64) (((double) Rand () / RAND_MAX) * (Limit - Start)) + Start;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Generate random MTRR BASE/MASK for a specified type.
 | 
						|
 | 
						|
  @param PhysicalAddressBits Physical address bits.
 | 
						|
  @param CacheType           Cache type.
 | 
						|
  @param MtrrPair            Return the random MTRR.
 | 
						|
  @param MtrrMemoryRange     Return the random memory range.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
GenerateRandomMtrrPair (
 | 
						|
  IN  UINT32                 PhysicalAddressBits,
 | 
						|
  IN  MTRR_MEMORY_CACHE_TYPE CacheType,
 | 
						|
  OUT MTRR_VARIABLE_SETTING  *MtrrPair,       OPTIONAL
 | 
						|
  OUT MTRR_MEMORY_RANGE      *MtrrMemoryRange OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  MSR_IA32_MTRR_PHYSBASE_REGISTER PhysBase;
 | 
						|
  MSR_IA32_MTRR_PHYSMASK_REGISTER PhysMask;
 | 
						|
  UINT32                          SizeShift;
 | 
						|
  UINT32                          BaseShift;
 | 
						|
  UINT64                          RandomBoundary;
 | 
						|
  UINT64                          MaxPhysicalAddress;
 | 
						|
  UINT64                          RangeSize;
 | 
						|
  UINT64                          RangeBase;
 | 
						|
  UINT64                          PhysBasePhyMaskValidBitsMask;
 | 
						|
 | 
						|
  MaxPhysicalAddress = 1ull << PhysicalAddressBits;
 | 
						|
  do {
 | 
						|
    SizeShift = Random32 (12, PhysicalAddressBits - 1);
 | 
						|
    RangeSize = 1ull << SizeShift;
 | 
						|
 | 
						|
    BaseShift = Random32 (SizeShift, PhysicalAddressBits - 1);
 | 
						|
    RandomBoundary = Random64 (0, 1ull << (PhysicalAddressBits - BaseShift));
 | 
						|
    RangeBase = RandomBoundary << BaseShift;
 | 
						|
  } while (RangeBase < SIZE_1MB || RangeBase > MaxPhysicalAddress - 1);
 | 
						|
 | 
						|
  PhysBasePhyMaskValidBitsMask = (MaxPhysicalAddress - 1) & 0xfffffffffffff000ULL;
 | 
						|
 | 
						|
  PhysBase.Uint64    = 0;
 | 
						|
  PhysBase.Bits.Type = CacheType;
 | 
						|
  PhysBase.Uint64   |= RangeBase & PhysBasePhyMaskValidBitsMask;
 | 
						|
  PhysMask.Uint64    = 0;
 | 
						|
  PhysMask.Bits.V    = 1;
 | 
						|
  PhysMask.Uint64   |= ((~RangeSize) + 1) & PhysBasePhyMaskValidBitsMask;
 | 
						|
 | 
						|
  if (MtrrPair != NULL) {
 | 
						|
    MtrrPair->Base = PhysBase.Uint64;
 | 
						|
    MtrrPair->Mask = PhysMask.Uint64;
 | 
						|
  }
 | 
						|
 | 
						|
  if (MtrrMemoryRange != NULL) {
 | 
						|
    MtrrMemoryRange->BaseAddress = RangeBase;
 | 
						|
    MtrrMemoryRange->Length      = RangeSize;
 | 
						|
    MtrrMemoryRange->Type        = CacheType;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Check whether the Range overlaps with any one in Ranges.
 | 
						|
 | 
						|
  @param Range  The memory range to check.
 | 
						|
  @param Ranges The memory ranges.
 | 
						|
  @param Count  Count of memory ranges.
 | 
						|
 | 
						|
  @return TRUE when overlap exists.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
RangesOverlap (
 | 
						|
  IN MTRR_MEMORY_RANGE *Range,
 | 
						|
  IN MTRR_MEMORY_RANGE *Ranges,
 | 
						|
  IN UINTN             Count
 | 
						|
  )
 | 
						|
{
 | 
						|
  while (Count-- != 0) {
 | 
						|
    //
 | 
						|
    // Two ranges overlap when:
 | 
						|
    // 1. range#2.base is in the middle of range#1
 | 
						|
    // 2. range#1.base is in the middle of range#2
 | 
						|
    //
 | 
						|
    if ((Range->BaseAddress <= Ranges[Count].BaseAddress && Ranges[Count].BaseAddress < Range->BaseAddress + Range->Length)
 | 
						|
     || (Ranges[Count].BaseAddress <= Range->BaseAddress && Range->BaseAddress < Ranges[Count].BaseAddress + Ranges[Count].Length)) {
 | 
						|
      return TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Generate random MTRRs.
 | 
						|
 | 
						|
  @param PhysicalAddressBits  Physical address bits.
 | 
						|
  @param RawMemoryRanges      Return the randomly generated MTRRs.
 | 
						|
  @param UcCount              Count of Uncacheable MTRRs.
 | 
						|
  @param WtCount              Count of Write Through MTRRs.
 | 
						|
  @param WbCount              Count of Write Back MTRRs.
 | 
						|
  @param WpCount              Count of Write Protected MTRRs.
 | 
						|
  @param WcCount              Count of Write Combine MTRRs.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
GenerateValidAndConfigurableMtrrPairs (
 | 
						|
  IN     UINT32                    PhysicalAddressBits,
 | 
						|
  IN OUT MTRR_MEMORY_RANGE         *RawMemoryRanges,
 | 
						|
  IN     UINT32                    UcCount,
 | 
						|
  IN     UINT32                    WtCount,
 | 
						|
  IN     UINT32                    WbCount,
 | 
						|
  IN     UINT32                    WpCount,
 | 
						|
  IN     UINT32                    WcCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32                          Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // 1. Generate UC, WT, WB in order.
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < UcCount; Index++) {
 | 
						|
    GenerateRandomMtrrPair (PhysicalAddressBits, CacheUncacheable, NULL, &RawMemoryRanges[Index]);
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = UcCount; Index < UcCount + WtCount; Index++) {
 | 
						|
    GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteThrough, NULL, &RawMemoryRanges[Index]);
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = UcCount + WtCount; Index < UcCount + WtCount + WbCount; Index++) {
 | 
						|
    GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteBack, NULL, &RawMemoryRanges[Index]);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 2. Generate WP MTRR and DO NOT overlap with WT, WB.
 | 
						|
  //
 | 
						|
  for (Index = UcCount + WtCount + WbCount; Index < UcCount + WtCount + WbCount + WpCount; Index++) {
 | 
						|
    GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteProtected, NULL, &RawMemoryRanges[Index]);
 | 
						|
    while (RangesOverlap (&RawMemoryRanges[Index], &RawMemoryRanges[UcCount], WtCount + WbCount)) {
 | 
						|
      GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteProtected, NULL, &RawMemoryRanges[Index]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 3. Generate WC MTRR and DO NOT overlap with WT, WB, WP.
 | 
						|
  //
 | 
						|
  for (Index = UcCount + WtCount + WbCount + WpCount; Index < UcCount + WtCount + WbCount + WpCount + WcCount; Index++) {
 | 
						|
    GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteCombining, NULL, &RawMemoryRanges[Index]);
 | 
						|
    while (RangesOverlap (&RawMemoryRanges[Index], &RawMemoryRanges[UcCount], WtCount + WbCount + WpCount)) {
 | 
						|
      GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteCombining, NULL, &RawMemoryRanges[Index]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return a random memory cache type.
 | 
						|
**/
 | 
						|
MTRR_MEMORY_CACHE_TYPE
 | 
						|
GenerateRandomCacheType (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
    return mMemoryCacheTypes[Random32 (0, ARRAY_SIZE (mMemoryCacheTypes) - 1)];
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Compare function used by qsort().
 | 
						|
**/
 | 
						|
 | 
						|
/**
 | 
						|
  Compare function used by qsort().
 | 
						|
 | 
						|
  @param Left   Left operand to compare.
 | 
						|
  @param Right  Right operand to compare.
 | 
						|
 | 
						|
  @retval 0  Left == Right
 | 
						|
  @retval -1 Left < Right
 | 
						|
  @retval 1  Left > Right
 | 
						|
**/
 | 
						|
INT32
 | 
						|
CompareFuncUint64 (
 | 
						|
  CONST VOID * Left,
 | 
						|
  CONST VOID * Right
 | 
						|
  )
 | 
						|
{
 | 
						|
    INT64 Delta;
 | 
						|
    Delta = (*(UINT64*)Left - *(UINT64*)Right);
 | 
						|
    if (Delta > 0) {
 | 
						|
      return 1;
 | 
						|
    } else if (Delta == 0) {
 | 
						|
      return 0;
 | 
						|
    } else {
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Determin the memory cache type for the Range.
 | 
						|
 | 
						|
  @param DefaultType Default cache type.
 | 
						|
  @param Range       The memory range to determin the cache type.
 | 
						|
  @param Ranges      The entire memory ranges.
 | 
						|
  @param RangeCount  Count of the entire memory ranges.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DetermineMemoryCacheType (
 | 
						|
  IN     MTRR_MEMORY_CACHE_TYPE DefaultType,
 | 
						|
  IN OUT MTRR_MEMORY_RANGE      *Range,
 | 
						|
  IN     MTRR_MEMORY_RANGE      *Ranges,
 | 
						|
  IN     UINT32                 RangeCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32 Index;
 | 
						|
  Range->Type = CacheInvalid;
 | 
						|
  for (Index = 0; Index < RangeCount; Index++) {
 | 
						|
    if (RangesOverlap (Range, &Ranges[Index], 1)) {
 | 
						|
      if (Ranges[Index].Type < Range->Type) {
 | 
						|
        Range->Type = Ranges[Index].Type;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Range->Type == CacheInvalid) {
 | 
						|
    Range->Type = DefaultType;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get the index of the element that does NOT equals to Array[Index].
 | 
						|
 | 
						|
  @param Index   Current element.
 | 
						|
  @param Array   Array to scan.
 | 
						|
  @param Count   Count of the array.
 | 
						|
 | 
						|
  @return Next element that doesn't equal to current one.
 | 
						|
**/
 | 
						|
UINT32
 | 
						|
GetNextDifferentElementInSortedArray (
 | 
						|
  IN UINT32 Index,
 | 
						|
  IN UINT64 *Array,
 | 
						|
  IN UINT32 Count
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT64 CurrentElement;
 | 
						|
  CurrentElement = Array[Index];
 | 
						|
  while (CurrentElement == Array[Index] && Index < Count) {
 | 
						|
    Index++;
 | 
						|
  }
 | 
						|
  return Index;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Remove the duplicates from the array.
 | 
						|
 | 
						|
  @param Array  The array to operate on.
 | 
						|
  @param Count  Count of the array.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
RemoveDuplicatesInSortedArray (
 | 
						|
  IN OUT UINT64 *Array,
 | 
						|
  IN OUT UINT32 *Count
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32 Index;
 | 
						|
  UINT32 NewCount;
 | 
						|
 | 
						|
  Index    = 0;
 | 
						|
  NewCount = 0;
 | 
						|
  while (Index < *Count) {
 | 
						|
    Array[NewCount] = Array[Index];
 | 
						|
    NewCount++;
 | 
						|
    Index = GetNextDifferentElementInSortedArray (Index, Array, *Count);
 | 
						|
  }
 | 
						|
  *Count = NewCount;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return TRUE when Address is in the Range.
 | 
						|
 | 
						|
  @param Address The address to check.
 | 
						|
  @param Range   The range to check.
 | 
						|
  @return TRUE when Address is in the Range.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
AddressInRange (
 | 
						|
  IN UINT64            Address,
 | 
						|
  IN MTRR_MEMORY_RANGE Range
 | 
						|
  )
 | 
						|
{
 | 
						|
    return (Address >= Range.BaseAddress) && (Address <= Range.BaseAddress + Range.Length - 1);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get the overlap bit flag.
 | 
						|
 | 
						|
  @param RawMemoryRanges     Raw memory ranges.
 | 
						|
  @param RawMemoryRangeCount Count of raw memory ranges.
 | 
						|
  @param Address             The address to check.
 | 
						|
**/
 | 
						|
UINT64
 | 
						|
GetOverlapBitFlag (
 | 
						|
  IN MTRR_MEMORY_RANGE *RawMemoryRanges,
 | 
						|
  IN UINT32            RawMemoryRangeCount,
 | 
						|
  IN UINT64            Address
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT64 OverlapBitFlag;
 | 
						|
  UINT32 Index;
 | 
						|
  OverlapBitFlag = 0;
 | 
						|
  for (Index = 0; Index < RawMemoryRangeCount; Index++) {
 | 
						|
    if (AddressInRange (Address, RawMemoryRanges[Index])) {
 | 
						|
      OverlapBitFlag |= (1ull << Index);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return OverlapBitFlag;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return the relationship between flags.
 | 
						|
 | 
						|
  @param Flag1 Flag 1
 | 
						|
  @param Flag2 Flag 2
 | 
						|
 | 
						|
  @retval 0   Flag1 == Flag2
 | 
						|
  @retval 1   Flag1 is a subset of Flag2
 | 
						|
  @retval 2   Flag2 is a subset of Flag1
 | 
						|
  @retval 3   No subset relations between Flag1 and Flag2.
 | 
						|
**/
 | 
						|
UINT32
 | 
						|
CheckOverlapBitFlagsRelation (
 | 
						|
  IN UINT64 Flag1,
 | 
						|
  IN UINT64 Flag2
 | 
						|
  )
 | 
						|
{
 | 
						|
    if (Flag1 == Flag2) return 0;
 | 
						|
    if ((Flag1 | Flag2) == Flag2) return 1;
 | 
						|
    if ((Flag1 | Flag2) == Flag1) return 2;
 | 
						|
    return 3;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return TRUE when the Endpoint is in any of the Ranges.
 | 
						|
 | 
						|
  @param Endpoint    The endpoint to check.
 | 
						|
  @param Ranges      The memory ranges.
 | 
						|
  @param RangeCount  Count of memory ranges.
 | 
						|
 | 
						|
  @retval TRUE  Endpoint is in one of the range.
 | 
						|
  @retval FALSE Endpoint is not in any of the ranges.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsEndpointInRanges (
 | 
						|
  IN UINT64            Endpoint,
 | 
						|
  IN MTRR_MEMORY_RANGE *Ranges,
 | 
						|
  IN UINTN             RangeCount
 | 
						|
  )
 | 
						|
{
 | 
						|
    UINT32 Index;
 | 
						|
    for (Index = 0; Index < RangeCount; Index++) {
 | 
						|
      if (AddressInRange (Endpoint, Ranges[Index])) {
 | 
						|
        return TRUE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Compact adjacent ranges of the same type.
 | 
						|
 | 
						|
  @param DefaultType                    Default memory type.
 | 
						|
  @param PhysicalAddressBits            Physical address bits.
 | 
						|
  @param EffectiveMtrrMemoryRanges      Memory ranges to compact.
 | 
						|
  @param EffectiveMtrrMemoryRangesCount Return the new count of memory ranges.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
CompactAndExtendEffectiveMtrrMemoryRanges (
 | 
						|
  IN     MTRR_MEMORY_CACHE_TYPE DefaultType,
 | 
						|
  IN     UINT32                 PhysicalAddressBits,
 | 
						|
  IN OUT MTRR_MEMORY_RANGE      **EffectiveMtrrMemoryRanges,
 | 
						|
  IN OUT UINTN                  *EffectiveMtrrMemoryRangesCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT64                        MaxAddress;
 | 
						|
  UINTN                         NewRangesCountAtMost;
 | 
						|
  MTRR_MEMORY_RANGE             *NewRanges;
 | 
						|
  UINTN                         NewRangesCountActual;
 | 
						|
  MTRR_MEMORY_RANGE             *CurrentRangeInNewRanges;
 | 
						|
  MTRR_MEMORY_CACHE_TYPE        CurrentRangeTypeInOldRanges;
 | 
						|
 | 
						|
  MTRR_MEMORY_RANGE             *OldRanges;
 | 
						|
  MTRR_MEMORY_RANGE             OldLastRange;
 | 
						|
  UINTN                         OldRangesIndex;
 | 
						|
 | 
						|
  NewRangesCountActual = 0;
 | 
						|
  NewRangesCountAtMost = *EffectiveMtrrMemoryRangesCount + 2;   // At most with 2 more range entries.
 | 
						|
  NewRanges            = (MTRR_MEMORY_RANGE *) calloc (NewRangesCountAtMost, sizeof (MTRR_MEMORY_RANGE));
 | 
						|
  OldRanges            = *EffectiveMtrrMemoryRanges;
 | 
						|
  if (OldRanges[0].BaseAddress > 0) {
 | 
						|
    NewRanges[NewRangesCountActual].BaseAddress = 0;
 | 
						|
    NewRanges[NewRangesCountActual].Length      = OldRanges[0].BaseAddress;
 | 
						|
    NewRanges[NewRangesCountActual].Type        = DefaultType;
 | 
						|
    NewRangesCountActual++;
 | 
						|
  }
 | 
						|
 | 
						|
  OldRangesIndex = 0;
 | 
						|
  while (OldRangesIndex < *EffectiveMtrrMemoryRangesCount) {
 | 
						|
    CurrentRangeTypeInOldRanges = OldRanges[OldRangesIndex].Type;
 | 
						|
    CurrentRangeInNewRanges = NULL;
 | 
						|
    if (NewRangesCountActual > 0)   // We need to check CurrentNewRange first before generate a new NewRange.
 | 
						|
    {
 | 
						|
      CurrentRangeInNewRanges = &NewRanges[NewRangesCountActual - 1];
 | 
						|
    }
 | 
						|
    if (CurrentRangeInNewRanges != NULL && CurrentRangeInNewRanges->Type == CurrentRangeTypeInOldRanges) {
 | 
						|
      CurrentRangeInNewRanges->Length += OldRanges[OldRangesIndex].Length;
 | 
						|
    } else {
 | 
						|
      NewRanges[NewRangesCountActual].BaseAddress = OldRanges[OldRangesIndex].BaseAddress;
 | 
						|
      NewRanges[NewRangesCountActual].Length     += OldRanges[OldRangesIndex].Length;
 | 
						|
      NewRanges[NewRangesCountActual].Type        = CurrentRangeTypeInOldRanges;
 | 
						|
      while (OldRangesIndex + 1 < *EffectiveMtrrMemoryRangesCount && OldRanges[OldRangesIndex + 1].Type == CurrentRangeTypeInOldRanges)
 | 
						|
      {
 | 
						|
        OldRangesIndex++;
 | 
						|
        NewRanges[NewRangesCountActual].Length += OldRanges[OldRangesIndex].Length;
 | 
						|
      }
 | 
						|
      NewRangesCountActual++;
 | 
						|
    }
 | 
						|
 | 
						|
    OldRangesIndex++;
 | 
						|
  }
 | 
						|
 | 
						|
  MaxAddress = (1ull << PhysicalAddressBits) - 1;
 | 
						|
  OldLastRange = OldRanges[(*EffectiveMtrrMemoryRangesCount) - 1];
 | 
						|
  CurrentRangeInNewRanges = &NewRanges[NewRangesCountActual - 1];
 | 
						|
  if (OldLastRange.BaseAddress + OldLastRange.Length - 1 < MaxAddress) {
 | 
						|
    if (CurrentRangeInNewRanges->Type == DefaultType) {
 | 
						|
      CurrentRangeInNewRanges->Length = MaxAddress - CurrentRangeInNewRanges->BaseAddress + 1;
 | 
						|
    } else {
 | 
						|
      NewRanges[NewRangesCountActual].BaseAddress = OldLastRange.BaseAddress + OldLastRange.Length;
 | 
						|
      NewRanges[NewRangesCountActual].Length = MaxAddress - NewRanges[NewRangesCountActual].BaseAddress + 1;
 | 
						|
      NewRanges[NewRangesCountActual].Type = DefaultType;
 | 
						|
      NewRangesCountActual++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  free (*EffectiveMtrrMemoryRanges);
 | 
						|
  *EffectiveMtrrMemoryRanges = NewRanges;
 | 
						|
  *EffectiveMtrrMemoryRangesCount = NewRangesCountActual;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Collect all the endpoints in the raw memory ranges.
 | 
						|
 | 
						|
  @param Endpoints           Return the collected endpoints.
 | 
						|
  @param EndPointCount       Return the count of endpoints.
 | 
						|
  @param RawMemoryRanges     Raw memory ranges.
 | 
						|
  @param RawMemoryRangeCount Count of raw memory ranges.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
CollectEndpoints (
 | 
						|
  IN OUT UINT64        *Endpoints,
 | 
						|
  IN OUT UINT32        *EndPointCount,
 | 
						|
  IN MTRR_MEMORY_RANGE *RawMemoryRanges,
 | 
						|
  IN UINT32            RawMemoryRangeCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32 Index;
 | 
						|
  UINT32 RawRangeIndex;
 | 
						|
 | 
						|
  ASSERT ((RawMemoryRangeCount << 1) == *EndPointCount);
 | 
						|
 | 
						|
  for (Index = 0; Index < *EndPointCount; Index += 2) {
 | 
						|
    RawRangeIndex = Index >> 1;
 | 
						|
    Endpoints[Index] = RawMemoryRanges[RawRangeIndex].BaseAddress;
 | 
						|
    Endpoints[Index + 1] = RawMemoryRanges[RawRangeIndex].BaseAddress + RawMemoryRanges[RawRangeIndex].Length - 1;
 | 
						|
  }
 | 
						|
 | 
						|
  qsort (Endpoints, *EndPointCount, sizeof (UINT64), CompareFuncUint64);
 | 
						|
  RemoveDuplicatesInSortedArray (Endpoints, EndPointCount);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Convert the MTRR BASE/MASK array to memory ranges.
 | 
						|
 | 
						|
  @param DefaultType          Default memory type.
 | 
						|
  @param PhysicalAddressBits  Physical address bits.
 | 
						|
  @param RawMemoryRanges      Raw memory ranges.
 | 
						|
  @param RawMemoryRangeCount  Count of raw memory ranges.
 | 
						|
  @param MemoryRanges         Memory ranges.
 | 
						|
  @param MemoryRangeCount     Count of memory ranges.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
GetEffectiveMemoryRanges (
 | 
						|
  IN MTRR_MEMORY_CACHE_TYPE DefaultType,
 | 
						|
  IN UINT32                 PhysicalAddressBits,
 | 
						|
  IN MTRR_MEMORY_RANGE      *RawMemoryRanges,
 | 
						|
  IN UINT32                 RawMemoryRangeCount,
 | 
						|
  OUT MTRR_MEMORY_RANGE     *MemoryRanges,
 | 
						|
  OUT UINTN                 *MemoryRangeCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                 Index;
 | 
						|
  UINT32                AllEndPointsCount;
 | 
						|
  UINT64                *AllEndPointsInclusive;
 | 
						|
  UINT32                AllRangePiecesCountMax;
 | 
						|
  MTRR_MEMORY_RANGE     *AllRangePieces;
 | 
						|
  UINTN                 AllRangePiecesCountActual;
 | 
						|
  UINT64                OverlapBitFlag1;
 | 
						|
  UINT64                OverlapBitFlag2;
 | 
						|
  INT32                 OverlapFlagRelation;
 | 
						|
 | 
						|
  if (RawMemoryRangeCount == 0) {
 | 
						|
    MemoryRanges[0].BaseAddress = 0;
 | 
						|
    MemoryRanges[0].Length      = (1ull << PhysicalAddressBits);
 | 
						|
    MemoryRanges[0].Type        = DefaultType;
 | 
						|
    *MemoryRangeCount = 1;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  AllEndPointsCount         = RawMemoryRangeCount << 1;
 | 
						|
  AllEndPointsInclusive     = calloc (AllEndPointsCount, sizeof (UINT64));
 | 
						|
  AllRangePiecesCountMax    = RawMemoryRangeCount * 3 + 1;
 | 
						|
  AllRangePieces            = calloc (AllRangePiecesCountMax, sizeof (MTRR_MEMORY_RANGE));
 | 
						|
  CollectEndpoints (AllEndPointsInclusive, &AllEndPointsCount, RawMemoryRanges, RawMemoryRangeCount);
 | 
						|
 | 
						|
  for (Index = 0, AllRangePiecesCountActual = 0; Index < AllEndPointsCount - 1; Index++) {
 | 
						|
    OverlapBitFlag1 = GetOverlapBitFlag (RawMemoryRanges, RawMemoryRangeCount, AllEndPointsInclusive[Index]);
 | 
						|
    OverlapBitFlag2 = GetOverlapBitFlag (RawMemoryRanges, RawMemoryRangeCount, AllEndPointsInclusive[Index + 1]);
 | 
						|
    OverlapFlagRelation = CheckOverlapBitFlagsRelation (OverlapBitFlag1, OverlapBitFlag2);
 | 
						|
    switch (OverlapFlagRelation) {
 | 
						|
      case 0:   // [1, 2]
 | 
						|
        AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
 | 
						|
        AllRangePieces[AllRangePiecesCountActual].Length      = AllEndPointsInclusive[Index + 1] - AllEndPointsInclusive[Index] + 1;
 | 
						|
        AllRangePiecesCountActual++;
 | 
						|
        break;
 | 
						|
      case 1:   // [1, 2)
 | 
						|
        AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
 | 
						|
        AllRangePieces[AllRangePiecesCountActual].Length      = (AllEndPointsInclusive[Index + 1] - 1) - AllEndPointsInclusive[Index] + 1;
 | 
						|
        AllRangePiecesCountActual++;
 | 
						|
        break;
 | 
						|
      case 2:   // (1, 2]
 | 
						|
        AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index] + 1;
 | 
						|
        AllRangePieces[AllRangePiecesCountActual].Length      = AllEndPointsInclusive[Index + 1] - (AllEndPointsInclusive[Index] + 1) + 1;
 | 
						|
        AllRangePiecesCountActual++;
 | 
						|
 | 
						|
        if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRangePieces, AllRangePiecesCountActual)) {
 | 
						|
          AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
 | 
						|
          AllRangePieces[AllRangePiecesCountActual].Length      = 1;
 | 
						|
          AllRangePiecesCountActual++;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      case 3:   // (1, 2)
 | 
						|
        AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index] + 1;
 | 
						|
        AllRangePieces[AllRangePiecesCountActual].Length      = (AllEndPointsInclusive[Index + 1] - 1) - (AllEndPointsInclusive[Index] + 1) + 1;
 | 
						|
        if (AllRangePieces[AllRangePiecesCountActual].Length == 0)   // Only in case 3 can exists Length=0, we should skip such "segment".
 | 
						|
          break;
 | 
						|
        AllRangePiecesCountActual++;
 | 
						|
        if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRangePieces, AllRangePiecesCountActual)) {
 | 
						|
          AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
 | 
						|
          AllRangePieces[AllRangePiecesCountActual].Length      = 1;
 | 
						|
          AllRangePiecesCountActual++;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      default:
 | 
						|
        ASSERT (FALSE);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < AllRangePiecesCountActual; Index++) {
 | 
						|
    DetermineMemoryCacheType (DefaultType, &AllRangePieces[Index], RawMemoryRanges, RawMemoryRangeCount);
 | 
						|
  }
 | 
						|
 | 
						|
  CompactAndExtendEffectiveMtrrMemoryRanges (DefaultType, PhysicalAddressBits, &AllRangePieces, &AllRangePiecesCountActual);
 | 
						|
  ASSERT (*MemoryRangeCount >= AllRangePiecesCountActual);
 | 
						|
  memcpy (MemoryRanges, AllRangePieces, AllRangePiecesCountActual * sizeof (MTRR_MEMORY_RANGE));
 | 
						|
  *MemoryRangeCount = AllRangePiecesCountActual;
 | 
						|
 | 
						|
  free (AllEndPointsInclusive);
 | 
						|
  free (AllRangePieces);
 | 
						|
}
 |