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 Retrieves CPUID information.
26 Executes the CPUID instruction with EAX set to the value specified by Index.
27 This function always returns Index.
28 If Eax is not NULL, then the value of EAX after CPUID is returned in Eax.
29 If Ebx is not NULL, then the value of EBX after CPUID is returned in Ebx.
30 If Ecx is not NULL, then the value of ECX after CPUID is returned in Ecx.
31 If Edx is not NULL, then the value of EDX after CPUID is returned in Edx.
32 This function is only available on IA-32 and x64.
34 @param Index The 32-bit value to load into EAX prior to invoking the CPUID
36 @param Eax The pointer to the 32-bit EAX value returned by the CPUID
37 instruction. This is an optional parameter that may be NULL.
38 @param Ebx The pointer to the 32-bit EBX value returned by the CPUID
39 instruction. This is an optional parameter that may be NULL.
40 @param Ecx The pointer to the 32-bit ECX value returned by the CPUID
41 instruction. This is an optional parameter that may be NULL.
42 @param Edx The pointer to the 32-bit EDX value returned by the CPUID
43 instruction. This is an optional parameter that may be NULL.
50 UnitTestMtrrLibAsmCpuid (
52 OUT UINT32
*Eax
, OPTIONAL
53 OUT UINT32
*Ebx
, OPTIONAL
54 OUT UINT32
*Ecx
, OPTIONAL
55 OUT UINT32
*Edx OPTIONAL
59 case CPUID_VERSION_INFO
:
61 *Edx
= mCpuidVersionInfoEdx
.Uint32
;
65 case CPUID_EXTENDED_FUNCTION
:
67 *Eax
= CPUID_VIR_PHY_ADDRESS_SIZE
;
71 case CPUID_VIR_PHY_ADDRESS_SIZE
:
73 *Eax
= mCpuidVirPhyAddressSizeEax
.Uint32
;
80 // Should never fall through to here
87 Returns a 64-bit Machine Specific Register(MSR).
89 Reads and returns the 64-bit MSR specified by Index. No parameter checking is
90 performed on Index, and some Index values may cause CPU exceptions. The
91 caller must either guarantee that Index is valid, or the caller must set up
92 exception handlers to catch the exceptions. This function is only available
95 @param MsrIndex The 32-bit MSR index to read.
97 @return The value of the MSR identified by MsrIndex.
102 UnitTestMtrrLibAsmReadMsr64(
108 for (Index
= 0; Index
< ARRAY_SIZE (mFixedMtrrsValue
); Index
++) {
109 if (MsrIndex
== mFixedMtrrsIndex
[Index
]) {
110 return mFixedMtrrsValue
[Index
];
114 if ((MsrIndex
>= MSR_IA32_MTRR_PHYSBASE0
) &&
115 (MsrIndex
<= MSR_IA32_MTRR_PHYSMASK0
+ (MTRR_NUMBER_OF_VARIABLE_MTRR
<< 1))) {
116 if (MsrIndex
% 2 == 0) {
117 Index
= (MsrIndex
- MSR_IA32_MTRR_PHYSBASE0
) >> 1;
118 return mVariableMtrrsPhysBase
[Index
].Uint64
;
120 Index
= (MsrIndex
- MSR_IA32_MTRR_PHYSMASK0
) >> 1;
121 return mVariableMtrrsPhysMask
[Index
].Uint64
;
125 if (MsrIndex
== MSR_IA32_MTRR_DEF_TYPE
) {
126 return mDefTypeMsr
.Uint64
;
129 if (MsrIndex
== MSR_IA32_MTRRCAP
) {
130 return mMtrrCapMsr
.Uint64
;
134 // Should never fall through to here
141 Writes a 64-bit value to a Machine Specific Register(MSR), and returns the
144 Writes the 64-bit value specified by Value to the MSR specified by Index. The
145 64-bit value written to the MSR is returned. No parameter checking is
146 performed on Index or Value, and some of these may cause CPU exceptions. The
147 caller must either guarantee that Index and Value are valid, or the caller
148 must establish proper exception handlers. This function is only available on
151 @param MsrIndex The 32-bit MSR index to write.
152 @param Value The 64-bit value to write to the MSR.
159 UnitTestMtrrLibAsmWriteMsr64(
166 for (Index
= 0; Index
< ARRAY_SIZE (mFixedMtrrsValue
); Index
++) {
167 if (MsrIndex
== mFixedMtrrsIndex
[Index
]) {
168 mFixedMtrrsValue
[Index
] = Value
;
173 if ((MsrIndex
>= MSR_IA32_MTRR_PHYSBASE0
) &&
174 (MsrIndex
<= MSR_IA32_MTRR_PHYSMASK0
+ (MTRR_NUMBER_OF_VARIABLE_MTRR
<< 1))) {
175 if (MsrIndex
% 2 == 0) {
176 Index
= (MsrIndex
- MSR_IA32_MTRR_PHYSBASE0
) >> 1;
177 mVariableMtrrsPhysBase
[Index
].Uint64
= Value
;
180 Index
= (MsrIndex
- MSR_IA32_MTRR_PHYSMASK0
) >> 1;
181 mVariableMtrrsPhysMask
[Index
].Uint64
= Value
;
186 if (MsrIndex
== MSR_IA32_MTRR_DEF_TYPE
) {
187 mDefTypeMsr
.Uint64
= Value
;
191 if (MsrIndex
== MSR_IA32_MTRRCAP
) {
192 mMtrrCapMsr
.Uint64
= Value
;
197 // Should never fall through to here
204 Initialize the MTRR registers.
206 @param SystemParameter System parameter that controls the MTRR registers initialization.
211 IN MTRR_LIB_SYSTEM_PARAMETER
*SystemParameter
216 SetMem (mFixedMtrrsValue
, sizeof (mFixedMtrrsValue
), SystemParameter
->DefaultCacheType
);
218 for (Index
= 0; Index
< ARRAY_SIZE (mVariableMtrrsPhysBase
); Index
++) {
219 mVariableMtrrsPhysBase
[Index
].Uint64
= 0;
220 mVariableMtrrsPhysBase
[Index
].Bits
.Type
= SystemParameter
->DefaultCacheType
;
221 mVariableMtrrsPhysBase
[Index
].Bits
.Reserved1
= 0;
223 mVariableMtrrsPhysMask
[Index
].Uint64
= 0;
224 mVariableMtrrsPhysMask
[Index
].Bits
.V
= 0;
225 mVariableMtrrsPhysMask
[Index
].Bits
.Reserved1
= 0;
228 mDefTypeMsr
.Bits
.E
= 1;
229 mDefTypeMsr
.Bits
.FE
= 1;
230 mDefTypeMsr
.Bits
.Type
= SystemParameter
->DefaultCacheType
;
231 mDefTypeMsr
.Bits
.Reserved1
= 0;
232 mDefTypeMsr
.Bits
.Reserved2
= 0;
233 mDefTypeMsr
.Bits
.Reserved3
= 0;
235 mMtrrCapMsr
.Bits
.SMRR
= 0;
236 mMtrrCapMsr
.Bits
.WC
= 0;
237 mMtrrCapMsr
.Bits
.VCNT
= SystemParameter
->VariableMtrrCount
;
238 mMtrrCapMsr
.Bits
.FIX
= SystemParameter
->FixedMtrrSupported
;
239 mMtrrCapMsr
.Bits
.Reserved1
= 0;
240 mMtrrCapMsr
.Bits
.Reserved2
= 0;
241 mMtrrCapMsr
.Bits
.Reserved3
= 0;
243 mCpuidVersionInfoEdx
.Bits
.MTRR
= SystemParameter
->MtrrSupported
;
244 mCpuidVirPhyAddressSizeEax
.Bits
.PhysicalAddressBits
= SystemParameter
->PhysicalAddressBits
;
247 // Hook BaseLib functions used by MtrrLib that require some emulation.
249 gUnitTestHostBaseLib
.X86
->AsmCpuid
= UnitTestMtrrLibAsmCpuid
;
250 gUnitTestHostBaseLib
.X86
->AsmReadMsr64
= UnitTestMtrrLibAsmReadMsr64
;
251 gUnitTestHostBaseLib
.X86
->AsmWriteMsr64
= UnitTestMtrrLibAsmWriteMsr64
;
253 return UNIT_TEST_PASSED
;
257 Initialize the MTRR registers.
259 @param Context System parameter that controls the MTRR registers initialization.
264 IN UNIT_TEST_CONTEXT Context
267 return InitializeMtrrRegs ((MTRR_LIB_SYSTEM_PARAMETER
*) Context
);
271 Collect the test result.
273 @param DefaultType Default memory type.
274 @param PhysicalAddressBits Physical address bits.
275 @param VariableMtrrCount Count of variable MTRRs.
276 @param Mtrrs MTRR settings to collect from.
277 @param Ranges Return the memory ranges.
278 @param RangeCount Return the count of memory ranges.
279 @param MtrrCount Return the count of variable MTRRs being used.
283 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
284 IN UINT32 PhysicalAddressBits
,
285 IN UINT32 VariableMtrrCount
,
286 IN MTRR_SETTINGS
*Mtrrs
,
287 OUT MTRR_MEMORY_RANGE
*Ranges
,
288 IN OUT UINTN
*RangeCount
,
289 OUT UINT32
*MtrrCount
293 UINT64 MtrrValidBitsMask
;
294 UINT64 MtrrValidAddressMask
;
295 MTRR_MEMORY_RANGE RawMemoryRanges
[ARRAY_SIZE (Mtrrs
->Variables
.Mtrr
)];
297 ASSERT (Mtrrs
!= NULL
);
298 ASSERT (VariableMtrrCount
<= ARRAY_SIZE (Mtrrs
->Variables
.Mtrr
));
300 MtrrValidBitsMask
= (1ull << PhysicalAddressBits
) - 1;
301 MtrrValidAddressMask
= MtrrValidBitsMask
& ~0xFFFull
;
304 for (Index
= 0; Index
< VariableMtrrCount
; Index
++) {
305 if (((MSR_IA32_MTRR_PHYSMASK_REGISTER
*) &Mtrrs
->Variables
.Mtrr
[Index
].Mask
)->Bits
.V
== 1) {
306 RawMemoryRanges
[*MtrrCount
].BaseAddress
= Mtrrs
->Variables
.Mtrr
[Index
].Base
& MtrrValidAddressMask
;
307 RawMemoryRanges
[*MtrrCount
].Type
=
308 ((MSR_IA32_MTRR_PHYSBASE_REGISTER
*) &Mtrrs
->Variables
.Mtrr
[Index
].Base
)->Bits
.Type
;
309 RawMemoryRanges
[*MtrrCount
].Length
=
310 ((~(Mtrrs
->Variables
.Mtrr
[Index
].Mask
& MtrrValidAddressMask
)) & MtrrValidBitsMask
) + 1;
315 GetEffectiveMemoryRanges (DefaultType
, PhysicalAddressBits
, RawMemoryRanges
, *MtrrCount
, Ranges
, RangeCount
);
319 Return a 32bit random number.
321 @param Start Start of the random number range.
322 @param Limit Limit of the random number range.
323 @return 32bit random number
331 return (UINT32
) (((double) rand () / RAND_MAX
) * (Limit
- Start
)) + Start
;
335 Return a 64bit random number.
337 @param Start Start of the random number range.
338 @param Limit Limit of the random number range.
339 @return 64bit random number
347 return (UINT64
) (((double) rand () / RAND_MAX
) * (Limit
- Start
)) + Start
;
351 Generate random MTRR BASE/MASK for a specified type.
353 @param PhysicalAddressBits Physical address bits.
354 @param CacheType Cache type.
355 @param MtrrPair Return the random MTRR.
356 @param MtrrMemoryRange Return the random memory range.
359 GenerateRandomMtrrPair (
360 IN UINT32 PhysicalAddressBits
,
361 IN MTRR_MEMORY_CACHE_TYPE CacheType
,
362 OUT MTRR_VARIABLE_SETTING
*MtrrPair
, OPTIONAL
363 OUT MTRR_MEMORY_RANGE
*MtrrMemoryRange OPTIONAL
366 MSR_IA32_MTRR_PHYSBASE_REGISTER PhysBase
;
367 MSR_IA32_MTRR_PHYSMASK_REGISTER PhysMask
;
370 UINT64 RandomBoundary
;
371 UINT64 MaxPhysicalAddress
;
374 UINT64 PhysBasePhyMaskValidBitsMask
;
376 MaxPhysicalAddress
= 1ull << PhysicalAddressBits
;
378 SizeShift
= Random32 (12, PhysicalAddressBits
- 1);
379 RangeSize
= 1ull << SizeShift
;
381 BaseShift
= Random32 (SizeShift
, PhysicalAddressBits
- 1);
382 RandomBoundary
= Random64 (0, 1ull << (PhysicalAddressBits
- BaseShift
));
383 RangeBase
= RandomBoundary
<< BaseShift
;
384 } while (RangeBase
< SIZE_1MB
|| RangeBase
> MaxPhysicalAddress
- 1);
386 PhysBasePhyMaskValidBitsMask
= (MaxPhysicalAddress
- 1) & 0xfffffffffffff000ULL
;
389 PhysBase
.Bits
.Type
= CacheType
;
390 PhysBase
.Uint64
|= RangeBase
& PhysBasePhyMaskValidBitsMask
;
393 PhysMask
.Uint64
|= ((~RangeSize
) + 1) & PhysBasePhyMaskValidBitsMask
;
395 if (MtrrPair
!= NULL
) {
396 MtrrPair
->Base
= PhysBase
.Uint64
;
397 MtrrPair
->Mask
= PhysMask
.Uint64
;
400 if (MtrrMemoryRange
!= NULL
) {
401 MtrrMemoryRange
->BaseAddress
= RangeBase
;
402 MtrrMemoryRange
->Length
= RangeSize
;
403 MtrrMemoryRange
->Type
= CacheType
;
409 Check whether the Range overlaps with any one in Ranges.
411 @param Range The memory range to check.
412 @param Ranges The memory ranges.
413 @param Count Count of memory ranges.
415 @return TRUE when overlap exists.
419 IN MTRR_MEMORY_RANGE
*Range
,
420 IN MTRR_MEMORY_RANGE
*Ranges
,
424 while (Count
-- != 0) {
426 // Two ranges overlap when:
427 // 1. range#2.base is in the middle of range#1
428 // 2. range#1.base is in the middle of range#2
430 if ((Range
->BaseAddress
<= Ranges
[Count
].BaseAddress
&& Ranges
[Count
].BaseAddress
< Range
->BaseAddress
+ Range
->Length
)
431 || (Ranges
[Count
].BaseAddress
<= Range
->BaseAddress
&& Range
->BaseAddress
< Ranges
[Count
].BaseAddress
+ Ranges
[Count
].Length
)) {
439 Generate random MTRRs.
441 @param PhysicalAddressBits Physical address bits.
442 @param RawMemoryRanges Return the randomly generated MTRRs.
443 @param UcCount Count of Uncacheable MTRRs.
444 @param WtCount Count of Write Through MTRRs.
445 @param WbCount Count of Write Back MTRRs.
446 @param WpCount Count of Write Protected MTRRs.
447 @param WcCount Count of Write Combine MTRRs.
450 GenerateValidAndConfigurableMtrrPairs (
451 IN UINT32 PhysicalAddressBits
,
452 IN OUT MTRR_MEMORY_RANGE
*RawMemoryRanges
,
463 // 1. Generate UC, WT, WB in order.
465 for (Index
= 0; Index
< UcCount
; Index
++) {
466 GenerateRandomMtrrPair (PhysicalAddressBits
, CacheUncacheable
, NULL
, &RawMemoryRanges
[Index
]);
469 for (Index
= UcCount
; Index
< UcCount
+ WtCount
; Index
++) {
470 GenerateRandomMtrrPair (PhysicalAddressBits
, CacheWriteThrough
, NULL
, &RawMemoryRanges
[Index
]);
473 for (Index
= UcCount
+ WtCount
; Index
< UcCount
+ WtCount
+ WbCount
; Index
++) {
474 GenerateRandomMtrrPair (PhysicalAddressBits
, CacheWriteBack
, NULL
, &RawMemoryRanges
[Index
]);
478 // 2. Generate WP MTRR and DO NOT overlap with WT, WB.
480 for (Index
= UcCount
+ WtCount
+ WbCount
; Index
< UcCount
+ WtCount
+ WbCount
+ WpCount
; Index
++) {
481 GenerateRandomMtrrPair (PhysicalAddressBits
, CacheWriteProtected
, NULL
, &RawMemoryRanges
[Index
]);
482 while (RangesOverlap (&RawMemoryRanges
[Index
], &RawMemoryRanges
[UcCount
], WtCount
+ WbCount
)) {
483 GenerateRandomMtrrPair (PhysicalAddressBits
, CacheWriteProtected
, NULL
, &RawMemoryRanges
[Index
]);
488 // 3. Generate WC MTRR and DO NOT overlap with WT, WB, WP.
490 for (Index
= UcCount
+ WtCount
+ WbCount
+ WpCount
; Index
< UcCount
+ WtCount
+ WbCount
+ WpCount
+ WcCount
; Index
++) {
491 GenerateRandomMtrrPair (PhysicalAddressBits
, CacheWriteCombining
, NULL
, &RawMemoryRanges
[Index
]);
492 while (RangesOverlap (&RawMemoryRanges
[Index
], &RawMemoryRanges
[UcCount
], WtCount
+ WbCount
+ WpCount
)) {
493 GenerateRandomMtrrPair (PhysicalAddressBits
, CacheWriteCombining
, NULL
, &RawMemoryRanges
[Index
]);
499 Return a random memory cache type.
501 MTRR_MEMORY_CACHE_TYPE
502 GenerateRandomCacheType (
506 return mMemoryCacheTypes
[Random32 (0, ARRAY_SIZE (mMemoryCacheTypes
) - 1)];
510 Compare function used by qsort().
514 Compare function used by qsort().
516 @param Left Left operand to compare.
517 @param Right Right operand to compare.
519 @retval 0 Left == Right
520 @retval -1 Left < Right
521 @retval 1 Left > Right
530 Delta
= (*(UINT64
*)Left
- *(UINT64
*)Right
);
533 } else if (Delta
== 0) {
541 Determin the memory cache type for the Range.
543 @param DefaultType Default cache type.
544 @param Range The memory range to determin the cache type.
545 @param Ranges The entire memory ranges.
546 @param RangeCount Count of the entire memory ranges.
549 DetermineMemoryCacheType (
550 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
551 IN OUT MTRR_MEMORY_RANGE
*Range
,
552 IN MTRR_MEMORY_RANGE
*Ranges
,
557 Range
->Type
= CacheInvalid
;
558 for (Index
= 0; Index
< RangeCount
; Index
++) {
559 if (RangesOverlap (Range
, &Ranges
[Index
], 1)) {
560 if (Ranges
[Index
].Type
< Range
->Type
) {
561 Range
->Type
= Ranges
[Index
].Type
;
566 if (Range
->Type
== CacheInvalid
) {
567 Range
->Type
= DefaultType
;
572 Get the index of the element that does NOT equals to Array[Index].
574 @param Index Current element.
575 @param Array Array to scan.
576 @param Count Count of the array.
578 @return Next element that doesn't equal to current one.
581 GetNextDifferentElementInSortedArray (
587 UINT64 CurrentElement
;
588 CurrentElement
= Array
[Index
];
589 while (CurrentElement
== Array
[Index
] && Index
< Count
) {
596 Remove the duplicates from the array.
598 @param Array The array to operate on.
599 @param Count Count of the array.
602 RemoveDuplicatesInSortedArray (
603 IN OUT UINT64
*Array
,
612 while (Index
< *Count
) {
613 Array
[NewCount
] = Array
[Index
];
615 Index
= GetNextDifferentElementInSortedArray (Index
, Array
, *Count
);
621 Return TRUE when Address is in the Range.
623 @param Address The address to check.
624 @param Range The range to check.
625 @return TRUE when Address is in the Range.
630 IN MTRR_MEMORY_RANGE Range
633 return (Address
>= Range
.BaseAddress
) && (Address
<= Range
.BaseAddress
+ Range
.Length
- 1);
637 Get the overlap bit flag.
639 @param RawMemoryRanges Raw memory ranges.
640 @param RawMemoryRangeCount Count of raw memory ranges.
641 @param Address The address to check.
645 IN MTRR_MEMORY_RANGE
*RawMemoryRanges
,
646 IN UINT32 RawMemoryRangeCount
,
650 UINT64 OverlapBitFlag
;
653 for (Index
= 0; Index
< RawMemoryRangeCount
; Index
++) {
654 if (AddressInRange (Address
, RawMemoryRanges
[Index
])) {
655 OverlapBitFlag
|= (1ull << Index
);
659 return OverlapBitFlag
;
663 Return the relationship between flags.
668 @retval 0 Flag1 == Flag2
669 @retval 1 Flag1 is a subset of Flag2
670 @retval 2 Flag2 is a subset of Flag1
671 @retval 3 No subset relations between Flag1 and Flag2.
674 CheckOverlapBitFlagsRelation (
679 if (Flag1
== Flag2
) return 0;
680 if ((Flag1
| Flag2
) == Flag2
) return 1;
681 if ((Flag1
| Flag2
) == Flag1
) return 2;
686 Return TRUE when the Endpoint is in any of the Ranges.
688 @param Endpoint The endpoint to check.
689 @param Ranges The memory ranges.
690 @param RangeCount Count of memory ranges.
692 @retval TRUE Endpoint is in one of the range.
693 @retval FALSE Endpoint is not in any of the ranges.
698 IN MTRR_MEMORY_RANGE
*Ranges
,
703 for (Index
= 0; Index
< RangeCount
; Index
++) {
704 if (AddressInRange (Endpoint
, Ranges
[Index
])) {
713 Compact adjacent ranges of the same type.
715 @param DefaultType Default memory type.
716 @param PhysicalAddressBits Physical address bits.
717 @param EffectiveMtrrMemoryRanges Memory ranges to compact.
718 @param EffectiveMtrrMemoryRangesCount Return the new count of memory ranges.
721 CompactAndExtendEffectiveMtrrMemoryRanges (
722 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
723 IN UINT32 PhysicalAddressBits
,
724 IN OUT MTRR_MEMORY_RANGE
**EffectiveMtrrMemoryRanges
,
725 IN OUT UINTN
*EffectiveMtrrMemoryRangesCount
729 UINTN NewRangesCountAtMost
;
730 MTRR_MEMORY_RANGE
*NewRanges
;
731 UINTN NewRangesCountActual
;
732 MTRR_MEMORY_RANGE
*CurrentRangeInNewRanges
;
733 MTRR_MEMORY_CACHE_TYPE CurrentRangeTypeInOldRanges
;
735 MTRR_MEMORY_RANGE
*OldRanges
;
736 MTRR_MEMORY_RANGE OldLastRange
;
737 UINTN OldRangesIndex
;
739 NewRangesCountActual
= 0;
740 NewRangesCountAtMost
= *EffectiveMtrrMemoryRangesCount
+ 2; // At most with 2 more range entries.
741 NewRanges
= (MTRR_MEMORY_RANGE
*) calloc (NewRangesCountAtMost
, sizeof (MTRR_MEMORY_RANGE
));
742 OldRanges
= *EffectiveMtrrMemoryRanges
;
743 if (OldRanges
[0].BaseAddress
> 0) {
744 NewRanges
[NewRangesCountActual
].BaseAddress
= 0;
745 NewRanges
[NewRangesCountActual
].Length
= OldRanges
[0].BaseAddress
;
746 NewRanges
[NewRangesCountActual
].Type
= DefaultType
;
747 NewRangesCountActual
++;
751 while (OldRangesIndex
< *EffectiveMtrrMemoryRangesCount
) {
752 CurrentRangeTypeInOldRanges
= OldRanges
[OldRangesIndex
].Type
;
753 CurrentRangeInNewRanges
= NULL
;
754 if (NewRangesCountActual
> 0) // We need to check CurrentNewRange first before generate a new NewRange.
756 CurrentRangeInNewRanges
= &NewRanges
[NewRangesCountActual
- 1];
758 if (CurrentRangeInNewRanges
!= NULL
&& CurrentRangeInNewRanges
->Type
== CurrentRangeTypeInOldRanges
) {
759 CurrentRangeInNewRanges
->Length
+= OldRanges
[OldRangesIndex
].Length
;
761 NewRanges
[NewRangesCountActual
].BaseAddress
= OldRanges
[OldRangesIndex
].BaseAddress
;
762 NewRanges
[NewRangesCountActual
].Length
+= OldRanges
[OldRangesIndex
].Length
;
763 NewRanges
[NewRangesCountActual
].Type
= CurrentRangeTypeInOldRanges
;
764 while (OldRangesIndex
+ 1 < *EffectiveMtrrMemoryRangesCount
&& OldRanges
[OldRangesIndex
+ 1].Type
== CurrentRangeTypeInOldRanges
)
767 NewRanges
[NewRangesCountActual
].Length
+= OldRanges
[OldRangesIndex
].Length
;
769 NewRangesCountActual
++;
775 MaxAddress
= (1ull << PhysicalAddressBits
) - 1;
776 OldLastRange
= OldRanges
[(*EffectiveMtrrMemoryRangesCount
) - 1];
777 CurrentRangeInNewRanges
= &NewRanges
[NewRangesCountActual
- 1];
778 if (OldLastRange
.BaseAddress
+ OldLastRange
.Length
- 1 < MaxAddress
) {
779 if (CurrentRangeInNewRanges
->Type
== DefaultType
) {
780 CurrentRangeInNewRanges
->Length
= MaxAddress
- CurrentRangeInNewRanges
->BaseAddress
+ 1;
782 NewRanges
[NewRangesCountActual
].BaseAddress
= OldLastRange
.BaseAddress
+ OldLastRange
.Length
;
783 NewRanges
[NewRangesCountActual
].Length
= MaxAddress
- NewRanges
[NewRangesCountActual
].BaseAddress
+ 1;
784 NewRanges
[NewRangesCountActual
].Type
= DefaultType
;
785 NewRangesCountActual
++;
789 free (*EffectiveMtrrMemoryRanges
);
790 *EffectiveMtrrMemoryRanges
= NewRanges
;
791 *EffectiveMtrrMemoryRangesCount
= NewRangesCountActual
;
795 Collect all the endpoints in the raw memory ranges.
797 @param Endpoints Return the collected endpoints.
798 @param EndPointCount Return the count of endpoints.
799 @param RawMemoryRanges Raw memory ranges.
800 @param RawMemoryRangeCount Count of raw memory ranges.
804 IN OUT UINT64
*Endpoints
,
805 IN OUT UINT32
*EndPointCount
,
806 IN MTRR_MEMORY_RANGE
*RawMemoryRanges
,
807 IN UINT32 RawMemoryRangeCount
811 UINT32 RawRangeIndex
;
813 ASSERT ((RawMemoryRangeCount
<< 1) == *EndPointCount
);
815 for (Index
= 0; Index
< *EndPointCount
; Index
+= 2) {
816 RawRangeIndex
= Index
>> 1;
817 Endpoints
[Index
] = RawMemoryRanges
[RawRangeIndex
].BaseAddress
;
818 Endpoints
[Index
+ 1] = RawMemoryRanges
[RawRangeIndex
].BaseAddress
+ RawMemoryRanges
[RawRangeIndex
].Length
- 1;
821 qsort (Endpoints
, *EndPointCount
, sizeof (UINT64
), CompareFuncUint64
);
822 RemoveDuplicatesInSortedArray (Endpoints
, EndPointCount
);
826 Convert the MTRR BASE/MASK array to memory ranges.
828 @param DefaultType Default memory type.
829 @param PhysicalAddressBits Physical address bits.
830 @param RawMemoryRanges Raw memory ranges.
831 @param RawMemoryRangeCount Count of raw memory ranges.
832 @param MemoryRanges Memory ranges.
833 @param MemoryRangeCount Count of memory ranges.
836 GetEffectiveMemoryRanges (
837 IN MTRR_MEMORY_CACHE_TYPE DefaultType
,
838 IN UINT32 PhysicalAddressBits
,
839 IN MTRR_MEMORY_RANGE
*RawMemoryRanges
,
840 IN UINT32 RawMemoryRangeCount
,
841 OUT MTRR_MEMORY_RANGE
*MemoryRanges
,
842 OUT UINTN
*MemoryRangeCount
846 UINT32 AllEndPointsCount
;
847 UINT64
*AllEndPointsInclusive
;
848 UINT32 AllRangePiecesCountMax
;
849 MTRR_MEMORY_RANGE
*AllRangePieces
;
850 UINTN AllRangePiecesCountActual
;
851 UINT64 OverlapBitFlag1
;
852 UINT64 OverlapBitFlag2
;
853 INT32 OverlapFlagRelation
;
855 if (RawMemoryRangeCount
== 0) {
856 MemoryRanges
[0].BaseAddress
= 0;
857 MemoryRanges
[0].Length
= (1ull << PhysicalAddressBits
);
858 MemoryRanges
[0].Type
= DefaultType
;
859 *MemoryRangeCount
= 1;
863 AllEndPointsCount
= RawMemoryRangeCount
<< 1;
864 AllEndPointsInclusive
= calloc (AllEndPointsCount
, sizeof (UINT64
));
865 AllRangePiecesCountMax
= RawMemoryRangeCount
* 3 + 1;
866 AllRangePieces
= calloc (AllRangePiecesCountMax
, sizeof (MTRR_MEMORY_RANGE
));
867 CollectEndpoints (AllEndPointsInclusive
, &AllEndPointsCount
, RawMemoryRanges
, RawMemoryRangeCount
);
869 for (Index
= 0, AllRangePiecesCountActual
= 0; Index
< AllEndPointsCount
- 1; Index
++) {
870 OverlapBitFlag1
= GetOverlapBitFlag (RawMemoryRanges
, RawMemoryRangeCount
, AllEndPointsInclusive
[Index
]);
871 OverlapBitFlag2
= GetOverlapBitFlag (RawMemoryRanges
, RawMemoryRangeCount
, AllEndPointsInclusive
[Index
+ 1]);
872 OverlapFlagRelation
= CheckOverlapBitFlagsRelation (OverlapBitFlag1
, OverlapBitFlag2
);
873 switch (OverlapFlagRelation
) {
875 AllRangePieces
[AllRangePiecesCountActual
].BaseAddress
= AllEndPointsInclusive
[Index
];
876 AllRangePieces
[AllRangePiecesCountActual
].Length
= AllEndPointsInclusive
[Index
+ 1] - AllEndPointsInclusive
[Index
] + 1;
877 AllRangePiecesCountActual
++;
880 AllRangePieces
[AllRangePiecesCountActual
].BaseAddress
= AllEndPointsInclusive
[Index
];
881 AllRangePieces
[AllRangePiecesCountActual
].Length
= (AllEndPointsInclusive
[Index
+ 1] - 1) - AllEndPointsInclusive
[Index
] + 1;
882 AllRangePiecesCountActual
++;
885 AllRangePieces
[AllRangePiecesCountActual
].BaseAddress
= AllEndPointsInclusive
[Index
] + 1;
886 AllRangePieces
[AllRangePiecesCountActual
].Length
= AllEndPointsInclusive
[Index
+ 1] - (AllEndPointsInclusive
[Index
] + 1) + 1;
887 AllRangePiecesCountActual
++;
889 if (!IsEndpointInRanges (AllEndPointsInclusive
[Index
], AllRangePieces
, AllRangePiecesCountActual
)) {
890 AllRangePieces
[AllRangePiecesCountActual
].BaseAddress
= AllEndPointsInclusive
[Index
];
891 AllRangePieces
[AllRangePiecesCountActual
].Length
= 1;
892 AllRangePiecesCountActual
++;
896 AllRangePieces
[AllRangePiecesCountActual
].BaseAddress
= AllEndPointsInclusive
[Index
] + 1;
897 AllRangePieces
[AllRangePiecesCountActual
].Length
= (AllEndPointsInclusive
[Index
+ 1] - 1) - (AllEndPointsInclusive
[Index
] + 1) + 1;
898 if (AllRangePieces
[AllRangePiecesCountActual
].Length
== 0) // Only in case 3 can exists Length=0, we should skip such "segment".
900 AllRangePiecesCountActual
++;
901 if (!IsEndpointInRanges (AllEndPointsInclusive
[Index
], AllRangePieces
, AllRangePiecesCountActual
)) {
902 AllRangePieces
[AllRangePiecesCountActual
].BaseAddress
= AllEndPointsInclusive
[Index
];
903 AllRangePieces
[AllRangePiecesCountActual
].Length
= 1;
904 AllRangePiecesCountActual
++;
912 for (Index
= 0; Index
< AllRangePiecesCountActual
; Index
++) {
913 DetermineMemoryCacheType (DefaultType
, &AllRangePieces
[Index
], RawMemoryRanges
, RawMemoryRangeCount
);
916 CompactAndExtendEffectiveMtrrMemoryRanges (DefaultType
, PhysicalAddressBits
, &AllRangePieces
, &AllRangePiecesCountActual
);
917 ASSERT (*MemoryRangeCount
>= AllRangePiecesCountActual
);
918 memcpy (MemoryRanges
, AllRangePieces
, AllRangePiecesCountActual
* sizeof (MTRR_MEMORY_RANGE
));
919 *MemoryRangeCount
= AllRangePiecesCountActual
;
921 free (AllEndPointsInclusive
);
922 free (AllRangePieces
);