123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017 |
- /** @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);
- }
|