]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MtrrLib/UnitTest/Support.c
4fc222bdee47cf0512ef9c013053c8ef859d5701
[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 BOOLEAN mRandomInput;
24 UINTN mNumberIndex = 0;
25 extern UINTN mNumbers[];
26 extern UINTN mNumberCount;
27
28 /**
29 Return a random number between 0 and RAND_MAX.
30
31 If mRandomInput is TRUE, the routine directly calls rand().
32 Otherwise, the routine returns the pre-generated numbers.
33
34 @return a number between 0 and RAND_MAX.
35 **/
36 UINTN
37 Rand (
38 VOID
39 )
40 {
41 if (mRandomInput) {
42 return rand ();
43 } else {
44 DEBUG ((DEBUG_INFO, "random: %d\n", mNumberIndex));
45 return mNumbers[mNumberIndex++ % (mNumberCount - 1)];
46 }
47 }
48
49 CHAR8 mContentTemplate[] = {
50 "/** @file\n"
51 " Pre-generated random number used by MtrrLib test.\n"
52 "\n"
53 " Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\n"
54 " SPDX-License-Identifier: BSD-2-Clause-Patent\n"
55 "**/\n"
56 "UINTN mNumberCount = %d;\n"
57 "UINTN mNumbers[] = {"
58 };
59
60 /**
61 Generate Count random numbers in FilePath.
62
63 @param FilePath The file path to put the generated random numbers.
64 @param Count Count of random numbers.
65 **/
66 VOID
67 GenerateRandomNumbers (
68 CHAR8 *FilePath,
69 UINTN Count
70 )
71 {
72 FILE *File;
73 UINTN Index;
74
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 ");
80 }
81 fprintf (File, " %d,", rand ());
82 }
83 fprintf (File, "\n};\n");
84 fclose (File);
85 }
86
87 /**
88 Retrieves CPUID information.
89
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.
97
98 @param Index The 32-bit value to load into EAX prior to invoking the CPUID
99 instruction.
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.
108
109 @return Index.
110
111 **/
112 UINT32
113 EFIAPI
114 UnitTestMtrrLibAsmCpuid (
115 IN UINT32 Index,
116 OUT UINT32 *Eax, OPTIONAL
117 OUT UINT32 *Ebx, OPTIONAL
118 OUT UINT32 *Ecx, OPTIONAL
119 OUT UINT32 *Edx OPTIONAL
120 )
121 {
122 switch (Index) {
123 case CPUID_VERSION_INFO:
124 if (Edx != NULL) {
125 *Edx = mCpuidVersionInfoEdx.Uint32;
126 }
127 return Index;
128 break;
129 case CPUID_EXTENDED_FUNCTION:
130 if (Eax != NULL) {
131 *Eax = CPUID_VIR_PHY_ADDRESS_SIZE;
132 }
133 return Index;
134 break;
135 case CPUID_VIR_PHY_ADDRESS_SIZE:
136 if (Eax != NULL) {
137 *Eax = mCpuidVirPhyAddressSizeEax.Uint32;
138 }
139 return Index;
140 break;
141 }
142
143 //
144 // Should never fall through to here
145 //
146 ASSERT(FALSE);
147 return Index;
148 }
149
150 /**
151 Returns a 64-bit Machine Specific Register(MSR).
152
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
157 on IA-32 and x64.
158
159 @param MsrIndex The 32-bit MSR index to read.
160
161 @return The value of the MSR identified by MsrIndex.
162
163 **/
164 UINT64
165 EFIAPI
166 UnitTestMtrrLibAsmReadMsr64(
167 IN UINT32 MsrIndex
168 )
169 {
170 UINT32 Index;
171
172 for (Index = 0; Index < ARRAY_SIZE (mFixedMtrrsValue); Index++) {
173 if (MsrIndex == mFixedMtrrsIndex[Index]) {
174 return mFixedMtrrsValue[Index];
175 }
176 }
177
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;
183 } else {
184 Index = (MsrIndex - MSR_IA32_MTRR_PHYSMASK0) >> 1;
185 return mVariableMtrrsPhysMask[Index].Uint64;
186 }
187 }
188
189 if (MsrIndex == MSR_IA32_MTRR_DEF_TYPE) {
190 return mDefTypeMsr.Uint64;
191 }
192
193 if (MsrIndex == MSR_IA32_MTRRCAP) {
194 return mMtrrCapMsr.Uint64;
195 }
196
197 //
198 // Should never fall through to here
199 //
200 ASSERT(FALSE);
201 return 0;
202 }
203
204 /**
205 Writes a 64-bit value to a Machine Specific Register(MSR), and returns the
206 value.
207
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
213 IA-32 and x64.
214
215 @param MsrIndex The 32-bit MSR index to write.
216 @param Value The 64-bit value to write to the MSR.
217
218 @return Value
219
220 **/
221 UINT64
222 EFIAPI
223 UnitTestMtrrLibAsmWriteMsr64(
224 IN UINT32 MsrIndex,
225 IN UINT64 Value
226 )
227 {
228 UINT32 Index;
229
230 for (Index = 0; Index < ARRAY_SIZE (mFixedMtrrsValue); Index++) {
231 if (MsrIndex == mFixedMtrrsIndex[Index]) {
232 mFixedMtrrsValue[Index] = Value;
233 return Value;
234 }
235 }
236
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;
242 return Value;
243 } else {
244 Index = (MsrIndex - MSR_IA32_MTRR_PHYSMASK0) >> 1;
245 mVariableMtrrsPhysMask[Index].Uint64 = Value;
246 return Value;
247 }
248 }
249
250 if (MsrIndex == MSR_IA32_MTRR_DEF_TYPE) {
251 mDefTypeMsr.Uint64 = Value;
252 return Value;
253 }
254
255 if (MsrIndex == MSR_IA32_MTRRCAP) {
256 mMtrrCapMsr.Uint64 = Value;
257 return Value;
258 }
259
260 //
261 // Should never fall through to here
262 //
263 ASSERT(FALSE);
264 return 0;
265 }
266
267 /**
268 Initialize the MTRR registers.
269
270 @param SystemParameter System parameter that controls the MTRR registers initialization.
271 **/
272 UNIT_TEST_STATUS
273 EFIAPI
274 InitializeMtrrRegs (
275 IN MTRR_LIB_SYSTEM_PARAMETER *SystemParameter
276 )
277 {
278 UINT32 Index;
279
280 SetMem (mFixedMtrrsValue, sizeof (mFixedMtrrsValue), SystemParameter->DefaultCacheType);
281
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;
286
287 mVariableMtrrsPhysMask[Index].Uint64 = 0;
288 mVariableMtrrsPhysMask[Index].Bits.V = 0;
289 mVariableMtrrsPhysMask[Index].Bits.Reserved1 = 0;
290 }
291
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;
298
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;
306
307 mCpuidVersionInfoEdx.Bits.MTRR = SystemParameter->MtrrSupported;
308 mCpuidVirPhyAddressSizeEax.Bits.PhysicalAddressBits = SystemParameter->PhysicalAddressBits;
309
310 //
311 // Hook BaseLib functions used by MtrrLib that require some emulation.
312 //
313 gUnitTestHostBaseLib.X86->AsmCpuid = UnitTestMtrrLibAsmCpuid;
314 gUnitTestHostBaseLib.X86->AsmReadMsr64 = UnitTestMtrrLibAsmReadMsr64;
315 gUnitTestHostBaseLib.X86->AsmWriteMsr64 = UnitTestMtrrLibAsmWriteMsr64;
316
317 return UNIT_TEST_PASSED;
318 }
319
320 /**
321 Initialize the MTRR registers.
322
323 @param Context System parameter that controls the MTRR registers initialization.
324 **/
325 UNIT_TEST_STATUS
326 EFIAPI
327 InitializeSystem (
328 IN UNIT_TEST_CONTEXT Context
329 )
330 {
331 return InitializeMtrrRegs ((MTRR_LIB_SYSTEM_PARAMETER *) Context);
332 }
333
334 /**
335 Collect the test result.
336
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.
344 **/
345 VOID
346 CollectTestResult (
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
354 )
355 {
356 UINTN Index;
357 UINT64 MtrrValidBitsMask;
358 UINT64 MtrrValidAddressMask;
359 MTRR_MEMORY_RANGE RawMemoryRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)];
360
361 ASSERT (Mtrrs != NULL);
362 ASSERT (VariableMtrrCount <= ARRAY_SIZE (Mtrrs->Variables.Mtrr));
363
364 MtrrValidBitsMask = (1ull << PhysicalAddressBits) - 1;
365 MtrrValidAddressMask = MtrrValidBitsMask & ~0xFFFull;
366
367 *MtrrCount = 0;
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;
375 (*MtrrCount)++;
376 }
377 }
378
379 GetEffectiveMemoryRanges (DefaultType, PhysicalAddressBits, RawMemoryRanges, *MtrrCount, Ranges, RangeCount);
380 }
381
382 /**
383 Return a 32bit random number.
384
385 @param Start Start of the random number range.
386 @param Limit Limit of the random number range.
387 @return 32bit random number
388 **/
389 UINT32
390 Random32 (
391 UINT32 Start,
392 UINT32 Limit
393 )
394 {
395 return (UINT32) (((double) Rand () / RAND_MAX) * (Limit - Start)) + Start;
396 }
397
398 /**
399 Return a 64bit random number.
400
401 @param Start Start of the random number range.
402 @param Limit Limit of the random number range.
403 @return 64bit random number
404 **/
405 UINT64
406 Random64 (
407 UINT64 Start,
408 UINT64 Limit
409 )
410 {
411 return (UINT64) (((double) Rand () / RAND_MAX) * (Limit - Start)) + Start;
412 }
413
414 /**
415 Generate random MTRR BASE/MASK for a specified type.
416
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.
421 **/
422 VOID
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
428 )
429 {
430 MSR_IA32_MTRR_PHYSBASE_REGISTER PhysBase;
431 MSR_IA32_MTRR_PHYSMASK_REGISTER PhysMask;
432 UINT32 SizeShift;
433 UINT32 BaseShift;
434 UINT64 RandomBoundary;
435 UINT64 MaxPhysicalAddress;
436 UINT64 RangeSize;
437 UINT64 RangeBase;
438 UINT64 PhysBasePhyMaskValidBitsMask;
439
440 MaxPhysicalAddress = 1ull << PhysicalAddressBits;
441 do {
442 SizeShift = Random32 (12, PhysicalAddressBits - 1);
443 RangeSize = 1ull << SizeShift;
444
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);
449
450 PhysBasePhyMaskValidBitsMask = (MaxPhysicalAddress - 1) & 0xfffffffffffff000ULL;
451
452 PhysBase.Uint64 = 0;
453 PhysBase.Bits.Type = CacheType;
454 PhysBase.Uint64 |= RangeBase & PhysBasePhyMaskValidBitsMask;
455 PhysMask.Uint64 = 0;
456 PhysMask.Bits.V = 1;
457 PhysMask.Uint64 |= ((~RangeSize) + 1) & PhysBasePhyMaskValidBitsMask;
458
459 if (MtrrPair != NULL) {
460 MtrrPair->Base = PhysBase.Uint64;
461 MtrrPair->Mask = PhysMask.Uint64;
462 }
463
464 if (MtrrMemoryRange != NULL) {
465 MtrrMemoryRange->BaseAddress = RangeBase;
466 MtrrMemoryRange->Length = RangeSize;
467 MtrrMemoryRange->Type = CacheType;
468 }
469 }
470
471
472 /**
473 Check whether the Range overlaps with any one in Ranges.
474
475 @param Range The memory range to check.
476 @param Ranges The memory ranges.
477 @param Count Count of memory ranges.
478
479 @return TRUE when overlap exists.
480 **/
481 BOOLEAN
482 RangesOverlap (
483 IN MTRR_MEMORY_RANGE *Range,
484 IN MTRR_MEMORY_RANGE *Ranges,
485 IN UINTN Count
486 )
487 {
488 while (Count-- != 0) {
489 //
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
493 //
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)) {
496 return TRUE;
497 }
498 }
499 return FALSE;
500 }
501
502 /**
503 Generate random MTRRs.
504
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.
512 **/
513 VOID
514 GenerateValidAndConfigurableMtrrPairs (
515 IN UINT32 PhysicalAddressBits,
516 IN OUT MTRR_MEMORY_RANGE *RawMemoryRanges,
517 IN UINT32 UcCount,
518 IN UINT32 WtCount,
519 IN UINT32 WbCount,
520 IN UINT32 WpCount,
521 IN UINT32 WcCount
522 )
523 {
524 UINT32 Index;
525
526 //
527 // 1. Generate UC, WT, WB in order.
528 //
529 for (Index = 0; Index < UcCount; Index++) {
530 GenerateRandomMtrrPair (PhysicalAddressBits, CacheUncacheable, NULL, &RawMemoryRanges[Index]);
531 }
532
533 for (Index = UcCount; Index < UcCount + WtCount; Index++) {
534 GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteThrough, NULL, &RawMemoryRanges[Index]);
535 }
536
537 for (Index = UcCount + WtCount; Index < UcCount + WtCount + WbCount; Index++) {
538 GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteBack, NULL, &RawMemoryRanges[Index]);
539 }
540
541 //
542 // 2. Generate WP MTRR and DO NOT overlap with WT, WB.
543 //
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]);
548 }
549 }
550
551 //
552 // 3. Generate WC MTRR and DO NOT overlap with WT, WB, WP.
553 //
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]);
558 }
559 }
560 }
561
562 /**
563 Return a random memory cache type.
564 **/
565 MTRR_MEMORY_CACHE_TYPE
566 GenerateRandomCacheType (
567 VOID
568 )
569 {
570 return mMemoryCacheTypes[Random32 (0, ARRAY_SIZE (mMemoryCacheTypes) - 1)];
571 }
572
573 /**
574 Compare function used by qsort().
575 **/
576
577 /**
578 Compare function used by qsort().
579
580 @param Left Left operand to compare.
581 @param Right Right operand to compare.
582
583 @retval 0 Left == Right
584 @retval -1 Left < Right
585 @retval 1 Left > Right
586 **/
587 INT32
588 CompareFuncUint64 (
589 CONST VOID * Left,
590 CONST VOID * Right
591 )
592 {
593 INT64 Delta;
594 Delta = (*(UINT64*)Left - *(UINT64*)Right);
595 if (Delta > 0) {
596 return 1;
597 } else if (Delta == 0) {
598 return 0;
599 } else {
600 return -1;
601 }
602 }
603
604 /**
605 Determin the memory cache type for the Range.
606
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.
611 **/
612 VOID
613 DetermineMemoryCacheType (
614 IN MTRR_MEMORY_CACHE_TYPE DefaultType,
615 IN OUT MTRR_MEMORY_RANGE *Range,
616 IN MTRR_MEMORY_RANGE *Ranges,
617 IN UINT32 RangeCount
618 )
619 {
620 UINT32 Index;
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;
626 }
627 }
628 }
629
630 if (Range->Type == CacheInvalid) {
631 Range->Type = DefaultType;
632 }
633 }
634
635 /**
636 Get the index of the element that does NOT equals to Array[Index].
637
638 @param Index Current element.
639 @param Array Array to scan.
640 @param Count Count of the array.
641
642 @return Next element that doesn't equal to current one.
643 **/
644 UINT32
645 GetNextDifferentElementInSortedArray (
646 IN UINT32 Index,
647 IN UINT64 *Array,
648 IN UINT32 Count
649 )
650 {
651 UINT64 CurrentElement;
652 CurrentElement = Array[Index];
653 while (CurrentElement == Array[Index] && Index < Count) {
654 Index++;
655 }
656 return Index;
657 }
658
659 /**
660 Remove the duplicates from the array.
661
662 @param Array The array to operate on.
663 @param Count Count of the array.
664 **/
665 VOID
666 RemoveDuplicatesInSortedArray (
667 IN OUT UINT64 *Array,
668 IN OUT UINT32 *Count
669 )
670 {
671 UINT32 Index;
672 UINT32 NewCount;
673
674 Index = 0;
675 NewCount = 0;
676 while (Index < *Count) {
677 Array[NewCount] = Array[Index];
678 NewCount++;
679 Index = GetNextDifferentElementInSortedArray (Index, Array, *Count);
680 }
681 *Count = NewCount;
682 }
683
684 /**
685 Return TRUE when Address is in the Range.
686
687 @param Address The address to check.
688 @param Range The range to check.
689 @return TRUE when Address is in the Range.
690 **/
691 BOOLEAN
692 AddressInRange (
693 IN UINT64 Address,
694 IN MTRR_MEMORY_RANGE Range
695 )
696 {
697 return (Address >= Range.BaseAddress) && (Address <= Range.BaseAddress + Range.Length - 1);
698 }
699
700 /**
701 Get the overlap bit flag.
702
703 @param RawMemoryRanges Raw memory ranges.
704 @param RawMemoryRangeCount Count of raw memory ranges.
705 @param Address The address to check.
706 **/
707 UINT64
708 GetOverlapBitFlag (
709 IN MTRR_MEMORY_RANGE *RawMemoryRanges,
710 IN UINT32 RawMemoryRangeCount,
711 IN UINT64 Address
712 )
713 {
714 UINT64 OverlapBitFlag;
715 UINT32 Index;
716 OverlapBitFlag = 0;
717 for (Index = 0; Index < RawMemoryRangeCount; Index++) {
718 if (AddressInRange (Address, RawMemoryRanges[Index])) {
719 OverlapBitFlag |= (1ull << Index);
720 }
721 }
722
723 return OverlapBitFlag;
724 }
725
726 /**
727 Return the relationship between flags.
728
729 @param Flag1 Flag 1
730 @param Flag2 Flag 2
731
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.
736 **/
737 UINT32
738 CheckOverlapBitFlagsRelation (
739 IN UINT64 Flag1,
740 IN UINT64 Flag2
741 )
742 {
743 if (Flag1 == Flag2) return 0;
744 if ((Flag1 | Flag2) == Flag2) return 1;
745 if ((Flag1 | Flag2) == Flag1) return 2;
746 return 3;
747 }
748
749 /**
750 Return TRUE when the Endpoint is in any of the Ranges.
751
752 @param Endpoint The endpoint to check.
753 @param Ranges The memory ranges.
754 @param RangeCount Count of memory ranges.
755
756 @retval TRUE Endpoint is in one of the range.
757 @retval FALSE Endpoint is not in any of the ranges.
758 **/
759 BOOLEAN
760 IsEndpointInRanges (
761 IN UINT64 Endpoint,
762 IN MTRR_MEMORY_RANGE *Ranges,
763 IN UINTN RangeCount
764 )
765 {
766 UINT32 Index;
767 for (Index = 0; Index < RangeCount; Index++) {
768 if (AddressInRange (Endpoint, Ranges[Index])) {
769 return TRUE;
770 }
771 }
772 return FALSE;
773 }
774
775
776 /**
777 Compact adjacent ranges of the same type.
778
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.
783 **/
784 VOID
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
790 )
791 {
792 UINT64 MaxAddress;
793 UINTN NewRangesCountAtMost;
794 MTRR_MEMORY_RANGE *NewRanges;
795 UINTN NewRangesCountActual;
796 MTRR_MEMORY_RANGE *CurrentRangeInNewRanges;
797 MTRR_MEMORY_CACHE_TYPE CurrentRangeTypeInOldRanges;
798
799 MTRR_MEMORY_RANGE *OldRanges;
800 MTRR_MEMORY_RANGE OldLastRange;
801 UINTN OldRangesIndex;
802
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++;
812 }
813
814 OldRangesIndex = 0;
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.
819 {
820 CurrentRangeInNewRanges = &NewRanges[NewRangesCountActual - 1];
821 }
822 if (CurrentRangeInNewRanges != NULL && CurrentRangeInNewRanges->Type == CurrentRangeTypeInOldRanges) {
823 CurrentRangeInNewRanges->Length += OldRanges[OldRangesIndex].Length;
824 } else {
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)
829 {
830 OldRangesIndex++;
831 NewRanges[NewRangesCountActual].Length += OldRanges[OldRangesIndex].Length;
832 }
833 NewRangesCountActual++;
834 }
835
836 OldRangesIndex++;
837 }
838
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;
845 } else {
846 NewRanges[NewRangesCountActual].BaseAddress = OldLastRange.BaseAddress + OldLastRange.Length;
847 NewRanges[NewRangesCountActual].Length = MaxAddress - NewRanges[NewRangesCountActual].BaseAddress + 1;
848 NewRanges[NewRangesCountActual].Type = DefaultType;
849 NewRangesCountActual++;
850 }
851 }
852
853 free (*EffectiveMtrrMemoryRanges);
854 *EffectiveMtrrMemoryRanges = NewRanges;
855 *EffectiveMtrrMemoryRangesCount = NewRangesCountActual;
856 }
857
858 /**
859 Collect all the endpoints in the raw memory ranges.
860
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.
865 **/
866 VOID
867 CollectEndpoints (
868 IN OUT UINT64 *Endpoints,
869 IN OUT UINT32 *EndPointCount,
870 IN MTRR_MEMORY_RANGE *RawMemoryRanges,
871 IN UINT32 RawMemoryRangeCount
872 )
873 {
874 UINT32 Index;
875 UINT32 RawRangeIndex;
876
877 ASSERT ((RawMemoryRangeCount << 1) == *EndPointCount);
878
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;
883 }
884
885 qsort (Endpoints, *EndPointCount, sizeof (UINT64), CompareFuncUint64);
886 RemoveDuplicatesInSortedArray (Endpoints, EndPointCount);
887 }
888
889 /**
890 Convert the MTRR BASE/MASK array to memory ranges.
891
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.
898 **/
899 VOID
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
907 )
908 {
909 UINTN Index;
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;
918
919 if (RawMemoryRangeCount == 0) {
920 MemoryRanges[0].BaseAddress = 0;
921 MemoryRanges[0].Length = (1ull << PhysicalAddressBits);
922 MemoryRanges[0].Type = DefaultType;
923 *MemoryRangeCount = 1;
924 return;
925 }
926
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);
932
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) {
938 case 0: // [1, 2]
939 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
940 AllRangePieces[AllRangePiecesCountActual].Length = AllEndPointsInclusive[Index + 1] - AllEndPointsInclusive[Index] + 1;
941 AllRangePiecesCountActual++;
942 break;
943 case 1: // [1, 2)
944 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
945 AllRangePieces[AllRangePiecesCountActual].Length = (AllEndPointsInclusive[Index + 1] - 1) - AllEndPointsInclusive[Index] + 1;
946 AllRangePiecesCountActual++;
947 break;
948 case 2: // (1, 2]
949 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index] + 1;
950 AllRangePieces[AllRangePiecesCountActual].Length = AllEndPointsInclusive[Index + 1] - (AllEndPointsInclusive[Index] + 1) + 1;
951 AllRangePiecesCountActual++;
952
953 if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRangePieces, AllRangePiecesCountActual)) {
954 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
955 AllRangePieces[AllRangePiecesCountActual].Length = 1;
956 AllRangePiecesCountActual++;
957 }
958 break;
959 case 3: // (1, 2)
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".
963 break;
964 AllRangePiecesCountActual++;
965 if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRangePieces, AllRangePiecesCountActual)) {
966 AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
967 AllRangePieces[AllRangePiecesCountActual].Length = 1;
968 AllRangePiecesCountActual++;
969 }
970 break;
971 default:
972 ASSERT (FALSE);
973 }
974 }
975
976 for (Index = 0; Index < AllRangePiecesCountActual; Index++) {
977 DetermineMemoryCacheType (DefaultType, &AllRangePieces[Index], RawMemoryRanges, RawMemoryRangeCount);
978 }
979
980 CompactAndExtendEffectiveMtrrMemoryRanges (DefaultType, PhysicalAddressBits, &AllRangePieces, &AllRangePiecesCountActual);
981 ASSERT (*MemoryRangeCount >= AllRangePiecesCountActual);
982 memcpy (MemoryRanges, AllRangePieces, AllRangePiecesCountActual * sizeof (MTRR_MEMORY_RANGE));
983 *MemoryRangeCount = AllRangePiecesCountActual;
984
985 free (AllEndPointsInclusive);
986 free (AllRangePieces);
987 }