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
Rand(VOID)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
GenerateRandomNumbers(CHAR8 * FilePath,UINTN Count)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
UnitTestMtrrLibAsmCpuid(IN UINT32 Index,OUT UINT32 * Eax,OPTIONAL OUT UINT32 * Ebx,OPTIONAL OUT UINT32 * Ecx,OPTIONAL OUT UINT32 * Edx OPTIONAL)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
UnitTestMtrrLibAsmReadMsr64(IN UINT32 MsrIndex)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
UnitTestMtrrLibAsmWriteMsr64(IN UINT32 MsrIndex,IN UINT64 Value)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
InitializeMtrrRegs(IN MTRR_LIB_SYSTEM_PARAMETER * SystemParameter)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
InitializeSystem(IN UNIT_TEST_CONTEXT Context)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
CollectTestResult(IN MTRR_MEMORY_CACHE_TYPE DefaultType,IN UINT32 PhysicalAddressBits,IN UINT32 VariableMtrrCount,IN MTRR_SETTINGS * Mtrrs,OUT MTRR_MEMORY_RANGE * Ranges,IN OUT UINTN * RangeCount,OUT UINT32 * MtrrCount)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
Random32(UINT32 Start,UINT32 Limit)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
Random64(UINT64 Start,UINT64 Limit)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
GenerateRandomMtrrPair(IN UINT32 PhysicalAddressBits,IN MTRR_MEMORY_CACHE_TYPE CacheType,OUT MTRR_VARIABLE_SETTING * MtrrPair,OPTIONAL OUT MTRR_MEMORY_RANGE * MtrrMemoryRange OPTIONAL)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
RangesOverlap(IN MTRR_MEMORY_RANGE * Range,IN MTRR_MEMORY_RANGE * Ranges,IN UINTN Count)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
GenerateValidAndConfigurableMtrrPairs(IN UINT32 PhysicalAddressBits,IN OUT MTRR_MEMORY_RANGE * RawMemoryRanges,IN UINT32 UcCount,IN UINT32 WtCount,IN UINT32 WbCount,IN UINT32 WpCount,IN UINT32 WcCount)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
GenerateRandomCacheType(VOID)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
CompareFuncUint64(CONST VOID * Left,CONST VOID * Right)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
DetermineMemoryCacheType(IN MTRR_MEMORY_CACHE_TYPE DefaultType,IN OUT MTRR_MEMORY_RANGE * Range,IN MTRR_MEMORY_RANGE * Ranges,IN UINT32 RangeCount)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
GetNextDifferentElementInSortedArray(IN UINT32 Index,IN UINT64 * Array,IN UINT32 Count)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
RemoveDuplicatesInSortedArray(IN OUT UINT64 * Array,IN OUT UINT32 * Count)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
AddressInRange(IN UINT64 Address,IN MTRR_MEMORY_RANGE Range)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
GetOverlapBitFlag(IN MTRR_MEMORY_RANGE * RawMemoryRanges,IN UINT32 RawMemoryRangeCount,IN UINT64 Address)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
CheckOverlapBitFlagsRelation(IN UINT64 Flag1,IN UINT64 Flag2)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
IsEndpointInRanges(IN UINT64 Endpoint,IN MTRR_MEMORY_RANGE * Ranges,IN UINTN RangeCount)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
CompactAndExtendEffectiveMtrrMemoryRanges(IN MTRR_MEMORY_CACHE_TYPE DefaultType,IN UINT32 PhysicalAddressBits,IN OUT MTRR_MEMORY_RANGE ** EffectiveMtrrMemoryRanges,IN OUT UINTN * EffectiveMtrrMemoryRangesCount)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
CollectEndpoints(IN OUT UINT64 * Endpoints,IN OUT UINT32 * EndPointCount,IN MTRR_MEMORY_RANGE * RawMemoryRanges,IN UINT32 RawMemoryRangeCount)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
GetEffectiveMemoryRanges(IN MTRR_MEMORY_CACHE_TYPE DefaultType,IN UINT32 PhysicalAddressBits,IN MTRR_MEMORY_RANGE * RawMemoryRanges,IN UINT32 RawMemoryRangeCount,OUT MTRR_MEMORY_RANGE * MemoryRanges,OUT UINTN * MemoryRangeCount)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 }
988