2 Unit tests of the MtrrLib instance of the MtrrLib class
4 Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "MtrrLibUnitTest.h"
11 MTRR_MEMORY_CACHE_TYPE mMemoryCacheTypes
[] = {
12 CacheUncacheable
, CacheWriteCombining
, CacheWriteThrough
, CacheWriteProtected
, CacheWriteBack
15 UINT64 mFixedMtrrsValue
[MTRR_NUMBER_OF_FIXED_MTRR
];
16 MSR_IA32_MTRR_PHYSBASE_REGISTER mVariableMtrrsPhysBase
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
17 MSR_IA32_MTRR_PHYSMASK_REGISTER mVariableMtrrsPhysMask
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
18 MSR_IA32_MTRR_DEF_TYPE_REGISTER mDefTypeMsr
;
19 MSR_IA32_MTRRCAP_REGISTER mMtrrCapMsr
;
20 CPUID_VERSION_INFO_EDX mCpuidVersionInfoEdx
;
21 CPUID_VIR_PHY_ADDRESS_SIZE_EAX mCpuidVirPhyAddressSizeEax
;
24 UINTN mNumberIndex
= 0;
25 extern UINTN mNumbers
[];
26 extern UINTN mNumberCount
;
29 Return a random number between 0 and RAND_MAX.
31 If mRandomInput is TRUE, the routine directly calls rand().
32 Otherwise, the routine returns the pre-generated numbers.
34 @return a number between 0 and RAND_MAX.
44 DEBUG ((DEBUG_INFO
, "random: %d\n", mNumberIndex
));
45 return mNumbers
[mNumberIndex
++ % (mNumberCount
- 1)];
49 CHAR8 mContentTemplate
[] = {
51 " Pre-generated random number used by MtrrLib test.\n"
53 " Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\n"
54 " SPDX-License-Identifier: BSD-2-Clause-Patent\n"
56 "UINTN mNumberCount = %d;\n"
57 "UINTN mNumbers[] = {"
61 Generate Count random numbers in FilePath.
63 @param FilePath The file path to put the generated random numbers.
64 @param Count Count of random numbers.
67 GenerateRandomNumbers (
75 File
= fopen (FilePath
, "w");
76 fprintf (File
, mContentTemplate
, Count
);
77 for (Index
= 0; Index
< Count
; Index
++) {
78 if (Index
% 10 == 0) {
79 fprintf (File
, "\n ");
81 fprintf (File
, " %d,", rand ());
83 fprintf (File
, "\n};\n");
88 Retrieves CPUID information.
90 Executes the CPUID instruction with EAX set to the value specified by Index.
91 This function always returns Index.
92 If Eax is not NULL, then the value of EAX after CPUID is returned in Eax.
93 If Ebx is not NULL, then the value of EBX after CPUID is returned in Ebx.
94 If Ecx is not NULL, then the value of ECX after CPUID is returned in Ecx.
95 If Edx is not NULL, then the value of EDX after CPUID is returned in Edx.
96 This function is only available on IA-32 and x64.
98 @param Index The 32-bit value to load into EAX prior to invoking the CPUID
100 @param Eax The pointer to the 32-bit EAX value returned by the CPUID
101 instruction. This is an optional parameter that may be NULL.
102 @param Ebx The pointer to the 32-bit EBX value returned by the CPUID
103 instruction. This is an optional parameter that may be NULL.
104 @param Ecx The pointer to the 32-bit ECX value returned by the CPUID
105 instruction. This is an optional parameter that may be NULL.
106 @param Edx The pointer to the 32-bit EDX value returned by the CPUID
107 instruction. This is an optional parameter that may be NULL.
114 UnitTestMtrrLibAsmCpuid (
116 OUT UINT32
*Eax
, OPTIONAL
117 OUT UINT32
*Ebx
, OPTIONAL
118 OUT UINT32
*Ecx
, OPTIONAL
119 OUT UINT32
*Edx OPTIONAL
123 case CPUID_VERSION_INFO
:
125 *Edx
= mCpuidVersionInfoEdx
.Uint32
;
129 case CPUID_EXTENDED_FUNCTION
:
131 *Eax
= CPUID_VIR_PHY_ADDRESS_SIZE
;
135 case CPUID_VIR_PHY_ADDRESS_SIZE
:
137 *Eax
= mCpuidVirPhyAddressSizeEax
.Uint32
;
144 // Should never fall through to here
151 Returns a 64-bit Machine Specific Register(MSR).
153 Reads and returns the 64-bit MSR specified by Index. No parameter checking is
154 performed on Index, and some Index values may cause CPU exceptions. The
155 caller must either guarantee that Index is valid, or the caller must set up
156 exception handlers to catch the exceptions. This function is only available
159 @param MsrIndex The 32-bit MSR index to read.
161 @return The value of the MSR identified by MsrIndex.
166 UnitTestMtrrLibAsmReadMsr64(
172 for (Index
= 0; Index
< ARRAY_SIZE (mFixedMtrrsValue
); Index
++) {
173 if (MsrIndex
== mFixedMtrrsIndex
[Index
]) {
174 return mFixedMtrrsValue
[Index
];
178 if ((MsrIndex
>= MSR_IA32_MTRR_PHYSBASE0
) &&
179 (MsrIndex
<= MSR_IA32_MTRR_PHYSMASK0
+ (MTRR_NUMBER_OF_VARIABLE_MTRR
<< 1))) {
180 if (MsrIndex
% 2 == 0) {
181 Index
= (MsrIndex
- MSR_IA32_MTRR_PHYSBASE0
) >> 1;
182 return mVariableMtrrsPhysBase
[Index
].Uint64
;
184 Index
= (MsrIndex
- MSR_IA32_MTRR_PHYSMASK0
) >> 1;
185 return mVariableMtrrsPhysMask
[Index
].Uint64
;
189 if (MsrIndex
== MSR_IA32_MTRR_DEF_TYPE
) {
190 return mDefTypeMsr
.Uint64
;
193 if (MsrIndex
== MSR_IA32_MTRRCAP
) {
194 return mMtrrCapMsr
.Uint64
;
198 // Should never fall through to here
205 Writes a 64-bit value to a Machine Specific Register(MSR), and returns the
208 Writes the 64-bit value specified by Value to the MSR specified by Index. The
209 64-bit value written to the MSR is returned. No parameter checking is
210 performed on Index or Value, and some of these may cause CPU exceptions. The
211 caller must either guarantee that Index and Value are valid, or the caller
212 must establish proper exception handlers. This function is only available on
215 @param MsrIndex The 32-bit MSR index to write.
216 @param Value The 64-bit value to write to the MSR.
223 UnitTestMtrrLibAsmWriteMsr64(
230 for (Index
= 0; Index
< ARRAY_SIZE (mFixedMtrrsValue
); Index
++) {
231 if (MsrIndex
== mFixedMtrrsIndex
[Index
]) {
232 mFixedMtrrsValue
[Index
] = Value
;
237 if ((MsrIndex
>= MSR_IA32_MTRR_PHYSBASE0
) &&
238 (MsrIndex
<= MSR_IA32_MTRR_PHYSMASK0
+ (MTRR_NUMBER_OF_VARIABLE_MTRR
<< 1))) {
239 if (MsrIndex
% 2 == 0) {
240 Index
= (MsrIndex
- MSR_IA32_MTRR_PHYSBASE0
) >> 1;
241 mVariableMtrrsPhysBase
[Index
].Uint64
= Value
;
244 Index
= (MsrIndex
- MSR_IA32_MTRR_PHYSMASK0
) >> 1;
245 mVariableMtrrsPhysMask
[Index
].Uint64
= Value
;
250 if (MsrIndex
== MSR_IA32_MTRR_DEF_TYPE
) {
251 mDefTypeMsr
.Uint64
= Value
;
255 if (MsrIndex
== MSR_IA32_MTRRCAP
) {
256 mMtrrCapMsr
.Uint64
= Value
;
261 // Should never fall through to here
268 Initialize the MTRR registers.
270 @param SystemParameter System parameter that controls the MTRR registers initialization.
275 IN MTRR_LIB_SYSTEM_PARAMETER
*SystemParameter
280 SetMem (mFixedMtrrsValue
, sizeof (mFixedMtrrsValue
), SystemParameter
->DefaultCacheType
);
282 for (Index
= 0; Index
< ARRAY_SIZE (mVariableMtrrsPhysBase
); Index
++) {
283 mVariableMtrrsPhysBase
[Index
].Uint64
= 0;
284 mVariableMtrrsPhysBase
[Index
].Bits
.Type
= SystemParameter
->DefaultCacheType
;
285 mVariableMtrrsPhysBase
[Index
].Bits
.Reserved1
= 0;
287 mVariableMtrrsPhysMask
[Index
].Uint64
= 0;
288 mVariableMtrrsPhysMask
[Index
].Bits
.V
= 0;
289 mVariableMtrrsPhysMask
[Index
].Bits
.Reserved1
= 0;
292 mDefTypeMsr
.Bits
.E
= 1;
293 mDefTypeMsr
.Bits
.FE
= 1;
294 mDefTypeMsr
.Bits
.Type
= SystemParameter
->DefaultCacheType
;
295 mDefTypeMsr
.Bits
.Reserved1
= 0;
296 mDefTypeMsr
.Bits
.Reserved2
= 0;
297 mDefTypeMsr
.Bits
.Reserved3
= 0;
299 mMtrrCapMsr
.Bits
.SMRR
= 0;
300 mMtrrCapMsr
.Bits
.WC
= 0;
301 mMtrrCapMsr
.Bits
.VCNT
= SystemParameter
->VariableMtrrCount
;
302 mMtrrCapMsr
.Bits
.FIX
= SystemParameter
->FixedMtrrSupported
;
303 mMtrrCapMsr
.Bits
.Reserved1
= 0;
304 mMtrrCapMsr
.Bits
.Reserved2
= 0;
305 mMtrrCapMsr
.Bits
.Reserved3
= 0;
307 mCpuidVersionInfoEdx
.Bits
.MTRR
= SystemParameter
->MtrrSupported
;
308 mCpuidVirPhyAddressSizeEax
.Bits
.PhysicalAddressBits
= SystemParameter
->PhysicalAddressBits
;
311 // Hook BaseLib functions used by MtrrLib that require some emulation.
313 gUnitTestHostBaseLib
.X86
->AsmCpuid
= UnitTestMtrrLibAsmCpuid
;
314 gUnitTestHostBaseLib
.X86
->AsmReadMsr64
= UnitTestMtrrLibAsmReadMsr64
;
315 gUnitTestHostBaseLib
.X86
->AsmWriteMsr64
= UnitTestMtrrLibAsmWriteMsr64
;
317 return UNIT_TEST_PASSED
;
321 Initialize the MTRR registers.
323 @param Context System parameter that controls the MTRR registers initialization.
328 IN UNIT_TEST_CONTEXT Context
331 return InitializeMtrrRegs ((MTRR_LIB_SYSTEM_PARAMETER
*) Context
);
335 Collect the test result.
337 @param DefaultType Default memory type.
338 @param PhysicalAddressBits Physical address bits.
339 @param VariableMtrrCount Count of variable MTRRs.
340 @param Mtrrs MTRR settings to collect from.
341 @param Ranges Return the memory ranges.
342 @param RangeCount Return the count of memory ranges.
343 @param MtrrCount Return the count of variable MTRRs being used.
347 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
348 IN UINT32 PhysicalAddressBits
,
349 IN UINT32 VariableMtrrCount
,
350 IN MTRR_SETTINGS
*Mtrrs
,
351 OUT MTRR_MEMORY_RANGE
*Ranges
,
352 IN OUT UINTN
*RangeCount
,
353 OUT UINT32
*MtrrCount
357 UINT64 MtrrValidBitsMask
;
358 UINT64 MtrrValidAddressMask
;
359 MTRR_MEMORY_RANGE RawMemoryRanges
[ARRAY_SIZE (Mtrrs
->Variables
.Mtrr
)];
361 ASSERT (Mtrrs
!= NULL
);
362 ASSERT (VariableMtrrCount
<= ARRAY_SIZE (Mtrrs
->Variables
.Mtrr
));
364 MtrrValidBitsMask
= (1ull << PhysicalAddressBits
) - 1;
365 MtrrValidAddressMask
= MtrrValidBitsMask
& ~0xFFFull
;
368 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
369 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER
*) &Mtrrs
->Variables
.Mtrr
[Index
].Mask
)->Bits
.V
== 1) {
370 RawMemoryRanges
[*MtrrCount
].BaseAddress
= Mtrrs
->Variables
.Mtrr
[Index
].Base
& MtrrValidAddressMask
;
371 RawMemoryRanges
[*MtrrCount
].Type
=
372 ((MSR_IA32_MTRR_PHYSBASE_REGISTER
*) &Mtrrs
->Variables
.Mtrr
[Index
].Base
)->Bits
.Type
;
373 RawMemoryRanges
[*MtrrCount
].Length
=
374 ((~(Mtrrs
->Variables
.Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
379 GetEffectiveMemoryRanges (DefaultType
, PhysicalAddressBits
, RawMemoryRanges
, *MtrrCount
, Ranges
, RangeCount
);
383 Return a 32bit random number.
385 @param Start Start of the random number range.
386 @param Limit Limit of the random number range.
387 @return 32bit random number
395 return (UINT32
) (((double) Rand () / RAND_MAX
) * (Limit
- Start
)) + Start
;
399 Return a 64bit random number.
401 @param Start Start of the random number range.
402 @param Limit Limit of the random number range.
403 @return 64bit random number
411 return (UINT64
) (((double) Rand () / RAND_MAX
) * (Limit
- Start
)) + Start
;
415 Generate random MTRR BASE/MASK for a specified type.
417 @param PhysicalAddressBits Physical address bits.
418 @param CacheType Cache type.
419 @param MtrrPair Return the random MTRR.
420 @param MtrrMemoryRange Return the random memory range.
423 GenerateRandomMtrrPair (
424 IN UINT32 PhysicalAddressBits
,
425 IN MTRR_MEMORY_CACHE_TYPE CacheType
,
426 OUT MTRR_VARIABLE_SETTING
*MtrrPair
, OPTIONAL
427 OUT MTRR_MEMORY_RANGE
*MtrrMemoryRange OPTIONAL
430 MSR_IA32_MTRR_PHYSBASE_REGISTER PhysBase
;
431 MSR_IA32_MTRR_PHYSMASK_REGISTER PhysMask
;
434 UINT64 RandomBoundary
;
435 UINT64 MaxPhysicalAddress
;
438 UINT64 PhysBasePhyMaskValidBitsMask
;
440 MaxPhysicalAddress
= 1ull << PhysicalAddressBits
;
442 SizeShift
= Random32 (12, PhysicalAddressBits
- 1);
443 RangeSize
= 1ull << SizeShift
;
445 BaseShift
= Random32 (SizeShift
, PhysicalAddressBits
- 1);
446 RandomBoundary
= Random64 (0, 1ull << (PhysicalAddressBits
- BaseShift
));
447 RangeBase
= RandomBoundary
<< BaseShift
;
448 } while (RangeBase
< SIZE_1MB
|| RangeBase
> MaxPhysicalAddress
- 1);
450 PhysBasePhyMaskValidBitsMask
= (MaxPhysicalAddress
- 1) & 0xfffffffffffff000ULL
;
453 PhysBase
.Bits
.Type
= CacheType
;
454 PhysBase
.Uint64
|= RangeBase
& PhysBasePhyMaskValidBitsMask
;
457 PhysMask
.Uint64
|= ((~RangeSize
) + 1) & PhysBasePhyMaskValidBitsMask
;
459 if (MtrrPair
!= NULL
) {
460 MtrrPair
->Base
= PhysBase
.Uint64
;
461 MtrrPair
->Mask
= PhysMask
.Uint64
;
464 if (MtrrMemoryRange
!= NULL
) {
465 MtrrMemoryRange
->BaseAddress
= RangeBase
;
466 MtrrMemoryRange
->Length
= RangeSize
;
467 MtrrMemoryRange
->Type
= CacheType
;
473 Check whether the Range overlaps with any one in Ranges.
475 @param Range The memory range to check.
476 @param Ranges The memory ranges.
477 @param Count Count of memory ranges.
479 @return TRUE when overlap exists.
483 IN MTRR_MEMORY_RANGE
*Range
,
484 IN MTRR_MEMORY_RANGE
*Ranges
,
488 while (Count
-- != 0) {
490 // Two ranges overlap when:
491 // 1. range#2.base is in the middle of range#1
492 // 2. range#1.base is in the middle of range#2
494 if ((Range
->BaseAddress
<= Ranges
[Count
].BaseAddress
&& Ranges
[Count
].BaseAddress
< Range
->BaseAddress
+ Range
->Length
)
495 || (Ranges
[Count
].BaseAddress
<= Range
->BaseAddress
&& Range
->BaseAddress
< Ranges
[Count
].BaseAddress
+ Ranges
[Count
].Length
)) {
503 Generate random MTRRs.
505 @param PhysicalAddressBits Physical address bits.
506 @param RawMemoryRanges Return the randomly generated MTRRs.
507 @param UcCount Count of Uncacheable MTRRs.
508 @param WtCount Count of Write Through MTRRs.
509 @param WbCount Count of Write Back MTRRs.
510 @param WpCount Count of Write Protected MTRRs.
511 @param WcCount Count of Write Combine MTRRs.
514 GenerateValidAndConfigurableMtrrPairs (
515 IN UINT32 PhysicalAddressBits
,
516 IN OUT MTRR_MEMORY_RANGE
*RawMemoryRanges
,
527 // 1. Generate UC, WT, WB in order.
529 for (Index
= 0; Index
< UcCount
; Index
++) {
530 GenerateRandomMtrrPair (PhysicalAddressBits
, CacheUncacheable
, NULL
, &RawMemoryRanges
[Index
]);
533 for (Index
= UcCount
; Index
< UcCount
+ WtCount
; Index
++) {
534 GenerateRandomMtrrPair (PhysicalAddressBits
, CacheWriteThrough
, NULL
, &RawMemoryRanges
[Index
]);
537 for (Index
= UcCount
+ WtCount
; Index
< UcCount
+ WtCount
+ WbCount
; Index
++) {
538 GenerateRandomMtrrPair (PhysicalAddressBits
, CacheWriteBack
, NULL
, &RawMemoryRanges
[Index
]);
542 // 2. Generate WP MTRR and DO NOT overlap with WT, WB.
544 for (Index
= UcCount
+ WtCount
+ WbCount
; Index
< UcCount
+ WtCount
+ WbCount
+ WpCount
; Index
++) {
545 GenerateRandomMtrrPair (PhysicalAddressBits
, CacheWriteProtected
, NULL
, &RawMemoryRanges
[Index
]);
546 while (RangesOverlap (&RawMemoryRanges
[Index
], &RawMemoryRanges
[UcCount
], WtCount
+ WbCount
)) {
547 GenerateRandomMtrrPair (PhysicalAddressBits
, CacheWriteProtected
, NULL
, &RawMemoryRanges
[Index
]);
552 // 3. Generate WC MTRR and DO NOT overlap with WT, WB, WP.
554 for (Index
= UcCount
+ WtCount
+ WbCount
+ WpCount
; Index
< UcCount
+ WtCount
+ WbCount
+ WpCount
+ WcCount
; Index
++) {
555 GenerateRandomMtrrPair (PhysicalAddressBits
, CacheWriteCombining
, NULL
, &RawMemoryRanges
[Index
]);
556 while (RangesOverlap (&RawMemoryRanges
[Index
], &RawMemoryRanges
[UcCount
], WtCount
+ WbCount
+ WpCount
)) {
557 GenerateRandomMtrrPair (PhysicalAddressBits
, CacheWriteCombining
, NULL
, &RawMemoryRanges
[Index
]);
563 Return a random memory cache type.
565 MTRR_MEMORY_CACHE_TYPE
566 GenerateRandomCacheType (
570 return mMemoryCacheTypes
[Random32 (0, ARRAY_SIZE (mMemoryCacheTypes
) - 1)];
574 Compare function used by qsort().
578 Compare function used by qsort().
580 @param Left Left operand to compare.
581 @param Right Right operand to compare.
583 @retval 0 Left == Right
584 @retval -1 Left < Right
585 @retval 1 Left > Right
594 Delta
= (*(UINT64
*)Left
- *(UINT64
*)Right
);
597 } else if (Delta
== 0) {
605 Determin the memory cache type for the Range.
607 @param DefaultType Default cache type.
608 @param Range The memory range to determin the cache type.
609 @param Ranges The entire memory ranges.
610 @param RangeCount Count of the entire memory ranges.
613 DetermineMemoryCacheType (
614 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
615 IN OUT MTRR_MEMORY_RANGE
*Range
,
616 IN MTRR_MEMORY_RANGE
*Ranges
,
621 Range
->Type
= CacheInvalid
;
622 for (Index
= 0; Index
< RangeCount
; Index
++) {
623 if (RangesOverlap (Range
, &Ranges
[Index
], 1)) {
624 if (Ranges
[Index
].Type
< Range
->Type
) {
625 Range
->Type
= Ranges
[Index
].Type
;
630 if (Range
->Type
== CacheInvalid
) {
631 Range
->Type
= DefaultType
;
636 Get the index of the element that does NOT equals to Array[Index].
638 @param Index Current element.
639 @param Array Array to scan.
640 @param Count Count of the array.
642 @return Next element that doesn't equal to current one.
645 GetNextDifferentElementInSortedArray (
651 UINT64 CurrentElement
;
652 CurrentElement
= Array
[Index
];
653 while (CurrentElement
== Array
[Index
] && Index
< Count
) {
660 Remove the duplicates from the array.
662 @param Array The array to operate on.
663 @param Count Count of the array.
666 RemoveDuplicatesInSortedArray (
667 IN OUT UINT64
*Array
,
676 while (Index
< *Count
) {
677 Array
[NewCount
] = Array
[Index
];
679 Index
= GetNextDifferentElementInSortedArray (Index
, Array
, *Count
);
685 Return TRUE when Address is in the Range.
687 @param Address The address to check.
688 @param Range The range to check.
689 @return TRUE when Address is in the Range.
694 IN MTRR_MEMORY_RANGE Range
697 return (Address
>= Range
.BaseAddress
) && (Address
<= Range
.BaseAddress
+ Range
.Length
- 1);
701 Get the overlap bit flag.
703 @param RawMemoryRanges Raw memory ranges.
704 @param RawMemoryRangeCount Count of raw memory ranges.
705 @param Address The address to check.
709 IN MTRR_MEMORY_RANGE
*RawMemoryRanges
,
710 IN UINT32 RawMemoryRangeCount
,
714 UINT64 OverlapBitFlag
;
717 for (Index
= 0; Index
< RawMemoryRangeCount
; Index
++) {
718 if (AddressInRange (Address
, RawMemoryRanges
[Index
])) {
719 OverlapBitFlag
|= (1ull << Index
);
723 return OverlapBitFlag
;
727 Return the relationship between flags.
732 @retval 0 Flag1 == Flag2
733 @retval 1 Flag1 is a subset of Flag2
734 @retval 2 Flag2 is a subset of Flag1
735 @retval 3 No subset relations between Flag1 and Flag2.
738 CheckOverlapBitFlagsRelation (
743 if (Flag1
== Flag2
) return 0;
744 if ((Flag1
| Flag2
) == Flag2
) return 1;
745 if ((Flag1
| Flag2
) == Flag1
) return 2;
750 Return TRUE when the Endpoint is in any of the Ranges.
752 @param Endpoint The endpoint to check.
753 @param Ranges The memory ranges.
754 @param RangeCount Count of memory ranges.
756 @retval TRUE Endpoint is in one of the range.
757 @retval FALSE Endpoint is not in any of the ranges.
762 IN MTRR_MEMORY_RANGE
*Ranges
,
767 for (Index
= 0; Index
< RangeCount
; Index
++) {
768 if (AddressInRange (Endpoint
, Ranges
[Index
])) {
777 Compact adjacent ranges of the same type.
779 @param DefaultType Default memory type.
780 @param PhysicalAddressBits Physical address bits.
781 @param EffectiveMtrrMemoryRanges Memory ranges to compact.
782 @param EffectiveMtrrMemoryRangesCount Return the new count of memory ranges.
785 CompactAndExtendEffectiveMtrrMemoryRanges (
786 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
787 IN UINT32 PhysicalAddressBits
,
788 IN OUT MTRR_MEMORY_RANGE
**EffectiveMtrrMemoryRanges
,
789 IN OUT UINTN
*EffectiveMtrrMemoryRangesCount
793 UINTN NewRangesCountAtMost
;
794 MTRR_MEMORY_RANGE
*NewRanges
;
795 UINTN NewRangesCountActual
;
796 MTRR_MEMORY_RANGE
*CurrentRangeInNewRanges
;
797 MTRR_MEMORY_CACHE_TYPE CurrentRangeTypeInOldRanges
;
799 MTRR_MEMORY_RANGE
*OldRanges
;
800 MTRR_MEMORY_RANGE OldLastRange
;
801 UINTN OldRangesIndex
;
803 NewRangesCountActual
= 0;
804 NewRangesCountAtMost
= *EffectiveMtrrMemoryRangesCount
+ 2; // At most with 2 more range entries.
805 NewRanges
= (MTRR_MEMORY_RANGE
*) calloc (NewRangesCountAtMost
, sizeof (MTRR_MEMORY_RANGE
));
806 OldRanges
= *EffectiveMtrrMemoryRanges
;
807 if (OldRanges
[0].BaseAddress
> 0) {
808 NewRanges
[NewRangesCountActual
].BaseAddress
= 0;
809 NewRanges
[NewRangesCountActual
].Length
= OldRanges
[0].BaseAddress
;
810 NewRanges
[NewRangesCountActual
].Type
= DefaultType
;
811 NewRangesCountActual
++;
815 while (OldRangesIndex
< *EffectiveMtrrMemoryRangesCount
) {
816 CurrentRangeTypeInOldRanges
= OldRanges
[OldRangesIndex
].Type
;
817 CurrentRangeInNewRanges
= NULL
;
818 if (NewRangesCountActual
> 0) // We need to check CurrentNewRange first before generate a new NewRange.
820 CurrentRangeInNewRanges
= &NewRanges
[NewRangesCountActual
- 1];
822 if (CurrentRangeInNewRanges
!= NULL
&& CurrentRangeInNewRanges
->Type
== CurrentRangeTypeInOldRanges
) {
823 CurrentRangeInNewRanges
->Length
+= OldRanges
[OldRangesIndex
].Length
;
825 NewRanges
[NewRangesCountActual
].BaseAddress
= OldRanges
[OldRangesIndex
].BaseAddress
;
826 NewRanges
[NewRangesCountActual
].Length
+= OldRanges
[OldRangesIndex
].Length
;
827 NewRanges
[NewRangesCountActual
].Type
= CurrentRangeTypeInOldRanges
;
828 while (OldRangesIndex
+ 1 < *EffectiveMtrrMemoryRangesCount
&& OldRanges
[OldRangesIndex
+ 1].Type
== CurrentRangeTypeInOldRanges
)
831 NewRanges
[NewRangesCountActual
].Length
+= OldRanges
[OldRangesIndex
].Length
;
833 NewRangesCountActual
++;
839 MaxAddress
= (1ull << PhysicalAddressBits
) - 1;
840 OldLastRange
= OldRanges
[(*EffectiveMtrrMemoryRangesCount
) - 1];
841 CurrentRangeInNewRanges
= &NewRanges
[NewRangesCountActual
- 1];
842 if (OldLastRange
.BaseAddress
+ OldLastRange
.Length
- 1 < MaxAddress
) {
843 if (CurrentRangeInNewRanges
->Type
== DefaultType
) {
844 CurrentRangeInNewRanges
->Length
= MaxAddress
- CurrentRangeInNewRanges
->BaseAddress
+ 1;
846 NewRanges
[NewRangesCountActual
].BaseAddress
= OldLastRange
.BaseAddress
+ OldLastRange
.Length
;
847 NewRanges
[NewRangesCountActual
].Length
= MaxAddress
- NewRanges
[NewRangesCountActual
].BaseAddress
+ 1;
848 NewRanges
[NewRangesCountActual
].Type
= DefaultType
;
849 NewRangesCountActual
++;
853 free (*EffectiveMtrrMemoryRanges
);
854 *EffectiveMtrrMemoryRanges
= NewRanges
;
855 *EffectiveMtrrMemoryRangesCount
= NewRangesCountActual
;
859 Collect all the endpoints in the raw memory ranges.
861 @param Endpoints Return the collected endpoints.
862 @param EndPointCount Return the count of endpoints.
863 @param RawMemoryRanges Raw memory ranges.
864 @param RawMemoryRangeCount Count of raw memory ranges.
868 IN OUT UINT64
*Endpoints
,
869 IN OUT UINT32
*EndPointCount
,
870 IN MTRR_MEMORY_RANGE
*RawMemoryRanges
,
871 IN UINT32 RawMemoryRangeCount
875 UINT32 RawRangeIndex
;
877 ASSERT ((RawMemoryRangeCount
<< 1) == *EndPointCount
);
879 for (Index
= 0; Index
< *EndPointCount
; Index
+= 2) {
880 RawRangeIndex
= Index
>> 1;
881 Endpoints
[Index
] = RawMemoryRanges
[RawRangeIndex
].BaseAddress
;
882 Endpoints
[Index
+ 1] = RawMemoryRanges
[RawRangeIndex
].BaseAddress
+ RawMemoryRanges
[RawRangeIndex
].Length
- 1;
885 qsort (Endpoints
, *EndPointCount
, sizeof (UINT64
), CompareFuncUint64
);
886 RemoveDuplicatesInSortedArray (Endpoints
, EndPointCount
);
890 Convert the MTRR BASE/MASK array to memory ranges.
892 @param DefaultType Default memory type.
893 @param PhysicalAddressBits Physical address bits.
894 @param RawMemoryRanges Raw memory ranges.
895 @param RawMemoryRangeCount Count of raw memory ranges.
896 @param MemoryRanges Memory ranges.
897 @param MemoryRangeCount Count of memory ranges.
900 GetEffectiveMemoryRanges (
901 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
902 IN UINT32 PhysicalAddressBits
,
903 IN MTRR_MEMORY_RANGE
*RawMemoryRanges
,
904 IN UINT32 RawMemoryRangeCount
,
905 OUT MTRR_MEMORY_RANGE
*MemoryRanges
,
906 OUT UINTN
*MemoryRangeCount
910 UINT32 AllEndPointsCount
;
911 UINT64
*AllEndPointsInclusive
;
912 UINT32 AllRangePiecesCountMax
;
913 MTRR_MEMORY_RANGE
*AllRangePieces
;
914 UINTN AllRangePiecesCountActual
;
915 UINT64 OverlapBitFlag1
;
916 UINT64 OverlapBitFlag2
;
917 INT32 OverlapFlagRelation
;
919 if (RawMemoryRangeCount
== 0) {
920 MemoryRanges
[0].BaseAddress
= 0;
921 MemoryRanges
[0].Length
= (1ull << PhysicalAddressBits
);
922 MemoryRanges
[0].Type
= DefaultType
;
923 *MemoryRangeCount
= 1;
927 AllEndPointsCount
= RawMemoryRangeCount
<< 1;
928 AllEndPointsInclusive
= calloc (AllEndPointsCount
, sizeof (UINT64
));
929 AllRangePiecesCountMax
= RawMemoryRangeCount
* 3 + 1;
930 AllRangePieces
= calloc (AllRangePiecesCountMax
, sizeof (MTRR_MEMORY_RANGE
));
931 CollectEndpoints (AllEndPointsInclusive
, &AllEndPointsCount
, RawMemoryRanges
, RawMemoryRangeCount
);
933 for (Index
= 0, AllRangePiecesCountActual
= 0; Index
< AllEndPointsCount
- 1; Index
++) {
934 OverlapBitFlag1
= GetOverlapBitFlag (RawMemoryRanges
, RawMemoryRangeCount
, AllEndPointsInclusive
[Index
]);
935 OverlapBitFlag2
= GetOverlapBitFlag (RawMemoryRanges
, RawMemoryRangeCount
, AllEndPointsInclusive
[Index
+ 1]);
936 OverlapFlagRelation
= CheckOverlapBitFlagsRelation (OverlapBitFlag1
, OverlapBitFlag2
);
937 switch (OverlapFlagRelation
) {
939 AllRangePieces
[AllRangePiecesCountActual
].BaseAddress
= AllEndPointsInclusive
[Index
];
940 AllRangePieces
[AllRangePiecesCountActual
].Length
= AllEndPointsInclusive
[Index
+ 1] - AllEndPointsInclusive
[Index
] + 1;
941 AllRangePiecesCountActual
++;
944 AllRangePieces
[AllRangePiecesCountActual
].BaseAddress
= AllEndPointsInclusive
[Index
];
945 AllRangePieces
[AllRangePiecesCountActual
].Length
= (AllEndPointsInclusive
[Index
+ 1] - 1) - AllEndPointsInclusive
[Index
] + 1;
946 AllRangePiecesCountActual
++;
949 AllRangePieces
[AllRangePiecesCountActual
].BaseAddress
= AllEndPointsInclusive
[Index
] + 1;
950 AllRangePieces
[AllRangePiecesCountActual
].Length
= AllEndPointsInclusive
[Index
+ 1] - (AllEndPointsInclusive
[Index
] + 1) + 1;
951 AllRangePiecesCountActual
++;
953 if (!IsEndpointInRanges (AllEndPointsInclusive
[Index
], AllRangePieces
, AllRangePiecesCountActual
)) {
954 AllRangePieces
[AllRangePiecesCountActual
].BaseAddress
= AllEndPointsInclusive
[Index
];
955 AllRangePieces
[AllRangePiecesCountActual
].Length
= 1;
956 AllRangePiecesCountActual
++;
960 AllRangePieces
[AllRangePiecesCountActual
].BaseAddress
= AllEndPointsInclusive
[Index
] + 1;
961 AllRangePieces
[AllRangePiecesCountActual
].Length
= (AllEndPointsInclusive
[Index
+ 1] - 1) - (AllEndPointsInclusive
[Index
] + 1) + 1;
962 if (AllRangePieces
[AllRangePiecesCountActual
].Length
== 0) // Only in case 3 can exists Length=0, we should skip such "segment".
964 AllRangePiecesCountActual
++;
965 if (!IsEndpointInRanges (AllEndPointsInclusive
[Index
], AllRangePieces
, AllRangePiecesCountActual
)) {
966 AllRangePieces
[AllRangePiecesCountActual
].BaseAddress
= AllEndPointsInclusive
[Index
];
967 AllRangePieces
[AllRangePiecesCountActual
].Length
= 1;
968 AllRangePiecesCountActual
++;
976 for (Index
= 0; Index
< AllRangePiecesCountActual
; Index
++) {
977 DetermineMemoryCacheType (DefaultType
, &AllRangePieces
[Index
], RawMemoryRanges
, RawMemoryRangeCount
);
980 CompactAndExtendEffectiveMtrrMemoryRanges (DefaultType
, PhysicalAddressBits
, &AllRangePieces
, &AllRangePiecesCountActual
);
981 ASSERT (*MemoryRangeCount
>= AllRangePiecesCountActual
);
982 memcpy (MemoryRanges
, AllRangePieces
, AllRangePiecesCountActual
* sizeof (MTRR_MEMORY_RANGE
));
983 *MemoryRangeCount
= AllRangePiecesCountActual
;
985 free (AllEndPointsInclusive
);
986 free (AllRangePieces
);