]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MtrrLib/UnitTest/Support.c
UefiCpuPkg/MtrrLib/UnitTest: Add host based unit test
[mirror_edk2.git] / UefiCpuPkg / Library / MtrrLib / UnitTest / Support.c
1 /** @file
2 Unit tests of the MtrrLib instance of the MtrrLib class
3
4 Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "MtrrLibUnitTest.h"
10
11 MTRR_MEMORY_CACHE_TYPE mMemoryCacheTypes[] = {
12 CacheUncacheable, CacheWriteCombining, CacheWriteThrough, CacheWriteProtected, CacheWriteBack
13 };
14
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;
22
23 /**
24 Retrieves CPUID information.
25
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.
33
34 @param Index The 32-bit value to load into EAX prior to invoking the CPUID
35 instruction.
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.
44
45 @return Index.
46
47 **/
48 UINT32
49 EFIAPI
50 UnitTestMtrrLibAsmCpuid (
51 IN UINT32 Index,
52 OUT UINT32 *Eax, OPTIONAL
53 OUT UINT32 *Ebx, OPTIONAL
54 OUT UINT32 *Ecx, OPTIONAL
55 OUT UINT32 *Edx OPTIONAL
56 )
57 {
58 switch (Index) {
59 case CPUID_VERSION_INFO:
60 if (Edx != NULL) {
61 *Edx = mCpuidVersionInfoEdx.Uint32;
62 }
63 return Index;
64 break;
65 case CPUID_EXTENDED_FUNCTION:
66 if (Eax != NULL) {
67 *Eax = CPUID_VIR_PHY_ADDRESS_SIZE;
68 }
69 return Index;
70 break;
71 case CPUID_VIR_PHY_ADDRESS_SIZE:
72 if (Eax != NULL) {
73 *Eax = mCpuidVirPhyAddressSizeEax.Uint32;
74 }
75 return Index;
76 break;
77 }
78
79 //
80 // Should never fall through to here
81 //
82 ASSERT(FALSE);
83 return Index;
84 }
85
86 /**
87 Returns a 64-bit Machine Specific Register(MSR).
88
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
93 on IA-32 and x64.
94
95 @param MsrIndex The 32-bit MSR index to read.
96
97 @return The value of the MSR identified by MsrIndex.
98
99 **/
100 UINT64
101 EFIAPI
102 UnitTestMtrrLibAsmReadMsr64(
103 IN UINT32 MsrIndex
104 )
105 {
106 UINT32 Index;
107
108 for (Index = 0; Index < ARRAY_SIZE (mFixedMtrrsValue); Index++) {
109 if (MsrIndex == mFixedMtrrsIndex[Index]) {
110 return mFixedMtrrsValue[Index];
111 }
112 }
113
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;
119 } else {
120 Index = (MsrIndex - MSR_IA32_MTRR_PHYSMASK0) >> 1;
121 return mVariableMtrrsPhysMask[Index].Uint64;
122 }
123 }
124
125 if (MsrIndex == MSR_IA32_MTRR_DEF_TYPE) {
126 return mDefTypeMsr.Uint64;
127 }
128
129 if (MsrIndex == MSR_IA32_MTRRCAP) {
130 return mMtrrCapMsr.Uint64;
131 }
132
133 //
134 // Should never fall through to here
135 //
136 ASSERT(FALSE);
137 return 0;
138 }
139
140 /**
141 Writes a 64-bit value to a Machine Specific Register(MSR), and returns the
142 value.
143
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
149 IA-32 and x64.
150
151 @param MsrIndex The 32-bit MSR index to write.
152 @param Value The 64-bit value to write to the MSR.
153
154 @return Value
155
156 **/
157 UINT64
158 EFIAPI
159 UnitTestMtrrLibAsmWriteMsr64(
160 IN UINT32 MsrIndex,
161 IN UINT64 Value
162 )
163 {
164 UINT32 Index;
165
166 for (Index = 0; Index < ARRAY_SIZE (mFixedMtrrsValue); Index++) {
167 if (MsrIndex == mFixedMtrrsIndex[Index]) {
168 mFixedMtrrsValue[Index] = Value;
169 return Value;
170 }
171 }
172
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;
178 return Value;
179 } else {
180 Index = (MsrIndex - MSR_IA32_MTRR_PHYSMASK0) >> 1;
181 mVariableMtrrsPhysMask[Index].Uint64 = Value;
182 return Value;
183 }
184 }
185
186 if (MsrIndex == MSR_IA32_MTRR_DEF_TYPE) {
187 mDefTypeMsr.Uint64 = Value;
188 return Value;
189 }
190
191 if (MsrIndex == MSR_IA32_MTRRCAP) {
192 mMtrrCapMsr.Uint64 = Value;
193 return Value;
194 }
195
196 //
197 // Should never fall through to here
198 //
199 ASSERT(FALSE);
200 return 0;
201 }
202
203 /**
204 Initialize the MTRR registers.
205
206 @param SystemParameter System parameter that controls the MTRR registers initialization.
207 **/
208 UNIT_TEST_STATUS
209 EFIAPI
210 InitializeMtrrRegs (
211 IN MTRR_LIB_SYSTEM_PARAMETER *SystemParameter
212 )
213 {
214 UINT32 Index;
215
216 SetMem (mFixedMtrrsValue, sizeof (mFixedMtrrsValue), SystemParameter->DefaultCacheType);
217
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;
222
223 mVariableMtrrsPhysMask[Index].Uint64 = 0;
224 mVariableMtrrsPhysMask[Index].Bits.V = 0;
225 mVariableMtrrsPhysMask[Index].Bits.Reserved1 = 0;
226 }
227
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;
234
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;
242
243 mCpuidVersionInfoEdx.Bits.MTRR = SystemParameter->MtrrSupported;
244 mCpuidVirPhyAddressSizeEax.Bits.PhysicalAddressBits = SystemParameter->PhysicalAddressBits;
245
246 //
247 // Hook BaseLib functions used by MtrrLib that require some emulation.
248 //
249 gUnitTestHostBaseLib.X86->AsmCpuid = UnitTestMtrrLibAsmCpuid;
250 gUnitTestHostBaseLib.X86->AsmReadMsr64 = UnitTestMtrrLibAsmReadMsr64;
251 gUnitTestHostBaseLib.X86->AsmWriteMsr64 = UnitTestMtrrLibAsmWriteMsr64;
252
253 return UNIT_TEST_PASSED;
254 }
255
256 /**
257 Initialize the MTRR registers.
258
259 @param Context System parameter that controls the MTRR registers initialization.
260 **/
261 UNIT_TEST_STATUS
262 EFIAPI
263 InitializeSystem (
264 IN UNIT_TEST_CONTEXT Context
265 )
266 {
267 return InitializeMtrrRegs ((MTRR_LIB_SYSTEM_PARAMETER *) Context);
268 }
269
270 /**
271 Collect the test result.
272
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.
280 **/
281 VOID
282 CollectTestResult (
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
290 )
291 {
292 UINTN Index;
293 UINT64 MtrrValidBitsMask;
294 UINT64 MtrrValidAddressMask;
295 MTRR_MEMORY_RANGE RawMemoryRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)];
296
297 ASSERT (Mtrrs != NULL);
298 ASSERT (VariableMtrrCount <= ARRAY_SIZE (Mtrrs->Variables.Mtrr));
299
300 MtrrValidBitsMask = (1ull << PhysicalAddressBits) - 1;
301 MtrrValidAddressMask = MtrrValidBitsMask & ~0xFFFull;
302
303 *MtrrCount = 0;
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;
311 (*MtrrCount)++;
312 }
313 }
314
315 GetEffectiveMemoryRanges (DefaultType, PhysicalAddressBits, RawMemoryRanges, *MtrrCount, Ranges, RangeCount);
316 }
317
318 /**
319 Return a 32bit random number.
320
321 @param Start Start of the random number range.
322 @param Limit Limit of the random number range.
323 @return 32bit random number
324 **/
325 UINT32
326 Random32 (
327 UINT32 Start,
328 UINT32 Limit
329 )
330 {
331 return (UINT32) (((double) rand () / RAND_MAX) * (Limit - Start)) + Start;
332 }
333
334 /**
335 Return a 64bit random number.
336
337 @param Start Start of the random number range.
338 @param Limit Limit of the random number range.
339 @return 64bit random number
340 **/
341 UINT64
342 Random64 (
343 UINT64 Start,
344 UINT64 Limit
345 )
346 {
347 return (UINT64) (((double) rand () / RAND_MAX) * (Limit - Start)) + Start;
348 }
349
350 /**
351 Generate random MTRR BASE/MASK for a specified type.
352
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.
357 **/
358 VOID
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
364 )
365 {
366 MSR_IA32_MTRR_PHYSBASE_REGISTER PhysBase;
367 MSR_IA32_MTRR_PHYSMASK_REGISTER PhysMask;
368 UINT32 SizeShift;
369 UINT32 BaseShift;
370 UINT64 RandomBoundary;
371 UINT64 MaxPhysicalAddress;
372 UINT64 RangeSize;
373 UINT64 RangeBase;
374 UINT64 PhysBasePhyMaskValidBitsMask;
375
376 MaxPhysicalAddress = 1ull << PhysicalAddressBits;
377 do {
378 SizeShift = Random32 (12, PhysicalAddressBits - 1);
379 RangeSize = 1ull << SizeShift;
380
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);
385
386 PhysBasePhyMaskValidBitsMask = (MaxPhysicalAddress - 1) & 0xfffffffffffff000ULL;
387
388 PhysBase.Uint64 = 0;
389 PhysBase.Bits.Type = CacheType;
390 PhysBase.Uint64 |= RangeBase & PhysBasePhyMaskValidBitsMask;
391 PhysMask.Uint64 = 0;
392 PhysMask.Bits.V = 1;
393 PhysMask.Uint64 |= ((~RangeSize) + 1) & PhysBasePhyMaskValidBitsMask;
394
395 if (MtrrPair != NULL) {
396 MtrrPair->Base = PhysBase.Uint64;
397 MtrrPair->Mask = PhysMask.Uint64;
398 }
399
400 if (MtrrMemoryRange != NULL) {
401 MtrrMemoryRange->BaseAddress = RangeBase;
402 MtrrMemoryRange->Length = RangeSize;
403 MtrrMemoryRange->Type = CacheType;
404 }
405 }
406
407
408 /**
409 Check whether the Range overlaps with any one in Ranges.
410
411 @param Range The memory range to check.
412 @param Ranges The memory ranges.
413 @param Count Count of memory ranges.
414
415 @return TRUE when overlap exists.
416 **/
417 BOOLEAN
418 RangesOverlap (
419 IN MTRR_MEMORY_RANGE *Range,
420 IN MTRR_MEMORY_RANGE *Ranges,
421 IN UINTN Count
422 )
423 {
424 while (Count-- != 0) {
425 //
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
429 //
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)) {
432 return TRUE;
433 }
434 }
435 return FALSE;
436 }
437
438 /**
439 Generate random MTRRs.
440
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.
448 **/
449 VOID
450 GenerateValidAndConfigurableMtrrPairs (
451 IN UINT32 PhysicalAddressBits,
452 IN OUT MTRR_MEMORY_RANGE *RawMemoryRanges,
453 IN UINT32 UcCount,
454 IN UINT32 WtCount,
455 IN UINT32 WbCount,
456 IN UINT32 WpCount,
457 IN UINT32 WcCount
458 )
459 {
460 UINT32 Index;
461
462 //
463 // 1. Generate UC, WT, WB in order.
464 //
465 for (Index = 0; Index < UcCount; Index++) {
466 GenerateRandomMtrrPair (PhysicalAddressBits, CacheUncacheable, NULL, &RawMemoryRanges[Index]);
467 }
468
469 for (Index = UcCount; Index < UcCount + WtCount; Index++) {
470 GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteThrough, NULL, &RawMemoryRanges[Index]);
471 }
472
473 for (Index = UcCount + WtCount; Index < UcCount + WtCount + WbCount; Index++) {
474 GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteBack, NULL, &RawMemoryRanges[Index]);
475 }
476
477 //
478 // 2. Generate WP MTRR and DO NOT overlap with WT, WB.
479 //
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]);
484 }
485 }
486
487 //
488 // 3. Generate WC MTRR and DO NOT overlap with WT, WB, WP.
489 //
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]);
494 }
495 }
496 }
497
498 /**
499 Return a random memory cache type.
500 **/
501 MTRR_MEMORY_CACHE_TYPE
502 GenerateRandomCacheType (
503 VOID
504 )
505 {
506 return mMemoryCacheTypes[Random32 (0, ARRAY_SIZE (mMemoryCacheTypes) - 1)];
507 }
508
509 /**
510 Compare function used by qsort().
511 **/
512
513 /**
514 Compare function used by qsort().
515
516 @param Left Left operand to compare.
517 @param Right Right operand to compare.
518
519 @retval 0 Left == Right
520 @retval -1 Left < Right
521 @retval 1 Left > Right
522 **/
523 INT32
524 CompareFuncUint64 (
525 CONST VOID * Left,
526 CONST VOID * Right
527 )
528 {
529 INT64 Delta;
530 Delta = (*(UINT64*)Left - *(UINT64*)Right);
531 if (Delta > 0) {
532 return 1;
533 } else if (Delta == 0) {
534 return 0;
535 } else {
536 return -1;
537 }
538 }
539
540 /**
541 Determin the memory cache type for the Range.
542
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.
547 **/
548 VOID
549 DetermineMemoryCacheType (
550 IN MTRR_MEMORY_CACHE_TYPE DefaultType,
551 IN OUT MTRR_MEMORY_RANGE *Range,
552 IN MTRR_MEMORY_RANGE *Ranges,
553 IN UINT32 RangeCount
554 )
555 {
556 UINT32 Index;
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;
562 }
563 }
564 }
565
566 if (Range->Type == CacheInvalid) {
567 Range->Type = DefaultType;
568 }
569 }
570
571 /**
572 Get the index of the element that does NOT equals to Array[Index].
573
574 @param Index Current element.
575 @param Array Array to scan.
576 @param Count Count of the array.
577
578 @return Next element that doesn't equal to current one.
579 **/
580 UINT32
581 GetNextDifferentElementInSortedArray (
582 IN UINT32 Index,
583 IN UINT64 *Array,
584 IN UINT32 Count
585 )
586 {
587 UINT64 CurrentElement;
588 CurrentElement = Array[Index];
589 while (CurrentElement == Array[Index] && Index < Count) {
590 Index++;
591 }
592 return Index;
593 }
594
595 /**
596 Remove the duplicates from the array.
597
598 @param Array The array to operate on.
599 @param Count Count of the array.
600 **/
601 VOID
602 RemoveDuplicatesInSortedArray (
603 IN OUT UINT64 *Array,
604 IN OUT UINT32 *Count
605 )
606 {
607 UINT32 Index;
608 UINT32 NewCount;
609
610 Index = 0;
611 NewCount = 0;
612 while (Index < *Count) {
613 Array[NewCount] = Array[Index];
614 NewCount++;
615 Index = GetNextDifferentElementInSortedArray (Index, Array, *Count);
616 }
617 *Count = NewCount;
618 }
619
620 /**
621 Return TRUE when Address is in the Range.
622
623 @param Address The address to check.
624 @param Range The range to check.
625 @return TRUE when Address is in the Range.
626 **/
627 BOOLEAN
628 AddressInRange (
629 IN UINT64 Address,
630 IN MTRR_MEMORY_RANGE Range
631 )
632 {
633 return (Address >= Range.BaseAddress) && (Address <= Range.BaseAddress + Range.Length - 1);
634 }
635
636 /**
637 Get the overlap bit flag.
638
639 @param RawMemoryRanges Raw memory ranges.
640 @param RawMemoryRangeCount Count of raw memory ranges.
641 @param Address The address to check.
642 **/
643 UINT64
644 GetOverlapBitFlag (
645 IN MTRR_MEMORY_RANGE *RawMemoryRanges,
646 IN UINT32 RawMemoryRangeCount,
647 IN UINT64 Address
648 )
649 {
650 UINT64 OverlapBitFlag;
651 UINT32 Index;
652 OverlapBitFlag = 0;
653 for (Index = 0; Index < RawMemoryRangeCount; Index++) {
654 if (AddressInRange (Address, RawMemoryRanges[Index])) {
655 OverlapBitFlag |= (1ull << Index);
656 }
657 }
658
659 return OverlapBitFlag;
660 }
661
662 /**
663 Return the relationship between flags.
664
665 @param Flag1 Flag 1
666 @param Flag2 Flag 2
667
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.
672 **/
673 UINT32
674 CheckOverlapBitFlagsRelation (
675 IN UINT64 Flag1,
676 IN UINT64 Flag2
677 )
678 {
679 if (Flag1 == Flag2) return 0;
680 if ((Flag1 | Flag2) == Flag2) return 1;
681 if ((Flag1 | Flag2) == Flag1) return 2;
682 return 3;
683 }
684
685 /**
686 Return TRUE when the Endpoint is in any of the Ranges.
687
688 @param Endpoint The endpoint to check.
689 @param Ranges The memory ranges.
690 @param RangeCount Count of memory ranges.
691
692 @retval TRUE Endpoint is in one of the range.
693 @retval FALSE Endpoint is not in any of the ranges.
694 **/
695 BOOLEAN
696 IsEndpointInRanges (
697 IN UINT64 Endpoint,
698 IN MTRR_MEMORY_RANGE *Ranges,
699 IN UINTN RangeCount
700 )
701 {
702 UINT32 Index;
703 for (Index = 0; Index < RangeCount; Index++) {
704 if (AddressInRange (Endpoint, Ranges[Index])) {
705 return TRUE;
706 }
707 }
708 return FALSE;
709 }
710
711
712 /**
713 Compact adjacent ranges of the same type.
714
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.
719 **/
720 VOID
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
726 )
727 {
728 UINT64 MaxAddress;
729 UINTN NewRangesCountAtMost;
730 MTRR_MEMORY_RANGE *NewRanges;
731 UINTN NewRangesCountActual;
732 MTRR_MEMORY_RANGE *CurrentRangeInNewRanges;
733 MTRR_MEMORY_CACHE_TYPE CurrentRangeTypeInOldRanges;
734
735 MTRR_MEMORY_RANGE *OldRanges;
736 MTRR_MEMORY_RANGE OldLastRange;
737 UINTN OldRangesIndex;
738
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++;
748 }
749
750 OldRangesIndex = 0;
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.
755 {
756 CurrentRangeInNewRanges = &NewRanges[NewRangesCountActual - 1];
757 }
758 if (CurrentRangeInNewRanges != NULL && CurrentRangeInNewRanges->Type == CurrentRangeTypeInOldRanges) {
759 CurrentRangeInNewRanges->Length += OldRanges[OldRangesIndex].Length;
760 } else {
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)
765 {
766 OldRangesIndex++;
767 NewRanges[NewRangesCountActual].Length += OldRanges[OldRangesIndex].Length;
768 }
769 NewRangesCountActual++;
770 }
771
772 OldRangesIndex++;
773 }
774
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;
781 } else {
782 NewRanges[NewRangesCountActual].BaseAddress = OldLastRange.BaseAddress + OldLastRange.Length;
783 NewRanges[NewRangesCountActual].Length = MaxAddress - NewRanges[NewRangesCountActual].BaseAddress + 1;
784 NewRanges[NewRangesCountActual].Type = DefaultType;
785 NewRangesCountActual++;
786 }
787 }
788
789 free (*EffectiveMtrrMemoryRanges);
790 *EffectiveMtrrMemoryRanges = NewRanges;
791 *EffectiveMtrrMemoryRangesCount = NewRangesCountActual;
792 }
793
794 /**
795 Collect all the endpoints in the raw memory ranges.
796
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.
801 **/
802 VOID
803 CollectEndpoints (
804 IN OUT UINT64 *Endpoints,
805 IN OUT UINT32 *EndPointCount,
806 IN MTRR_MEMORY_RANGE *RawMemoryRanges,
807 IN UINT32 RawMemoryRangeCount
808 )
809 {
810 UINT32 Index;
811 UINT32 RawRangeIndex;
812
813 ASSERT ((RawMemoryRangeCount << 1) == *EndPointCount);
814
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;
819 }
820
821 qsort (Endpoints, *EndPointCount, sizeof (UINT64), CompareFuncUint64);
822 RemoveDuplicatesInSortedArray (Endpoints, EndPointCount);
823 }
824
825 /**
826 Convert the MTRR BASE/MASK array to memory ranges.
827
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.
834 **/
835 VOID
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
843 )
844 {
845 UINTN Index;
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;
854
855 if (RawMemoryRangeCount == 0) {
856 MemoryRanges[0].BaseAddress = 0;
857 MemoryRanges[0].Length = (1ull << PhysicalAddressBits);
858 MemoryRanges[0].Type = DefaultType;
859 *MemoryRangeCount = 1;
860 return;
861 }
862
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);
868
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) {
874 case 0: // [1, 2]
875 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
876 AllRangePieces[AllRangePiecesCountActual].Length = AllEndPointsInclusive[Index + 1] - AllEndPointsInclusive[Index] + 1;
877 AllRangePiecesCountActual++;
878 break;
879 case 1: // [1, 2)
880 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
881 AllRangePieces[AllRangePiecesCountActual].Length = (AllEndPointsInclusive[Index + 1] - 1) - AllEndPointsInclusive[Index] + 1;
882 AllRangePiecesCountActual++;
883 break;
884 case 2: // (1, 2]
885 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index] + 1;
886 AllRangePieces[AllRangePiecesCountActual].Length = AllEndPointsInclusive[Index + 1] - (AllEndPointsInclusive[Index] + 1) + 1;
887 AllRangePiecesCountActual++;
888
889 if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRangePieces, AllRangePiecesCountActual)) {
890 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
891 AllRangePieces[AllRangePiecesCountActual].Length = 1;
892 AllRangePiecesCountActual++;
893 }
894 break;
895 case 3: // (1, 2)
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".
899 break;
900 AllRangePiecesCountActual++;
901 if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRangePieces, AllRangePiecesCountActual)) {
902 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
903 AllRangePieces[AllRangePiecesCountActual].Length = 1;
904 AllRangePiecesCountActual++;
905 }
906 break;
907 default:
908 ASSERT (FALSE);
909 }
910 }
911
912 for (Index = 0; Index < AllRangePiecesCountActual; Index++) {
913 DetermineMemoryCacheType (DefaultType, &AllRangePieces[Index], RawMemoryRanges, RawMemoryRangeCount);
914 }
915
916 CompactAndExtendEffectiveMtrrMemoryRanges (DefaultType, PhysicalAddressBits, &AllRangePieces, &AllRangePiecesCountActual);
917 ASSERT (*MemoryRangeCount >= AllRangePiecesCountActual);
918 memcpy (MemoryRanges, AllRangePieces, AllRangePiecesCountActual * sizeof (MTRR_MEMORY_RANGE));
919 *MemoryRangeCount = AllRangePiecesCountActual;
920
921 free (AllEndPointsInclusive);
922 free (AllRangePieces);
923 }