1 /** @file
2   MTRR setting library
3 
4   @par Note:
5     Most of services in this library instance are suggested to be invoked by BSP only,
6     except for MtrrSetAllMtrrs() which is used to sync BSP's MTRR setting to APs.
7 
8   Copyright (c) 2008 - 2019, Intel Corporation. All rights reserved.<BR>
9   SPDX-License-Identifier: BSD-2-Clause-Patent
10 
11 **/
12 
13 #include <Uefi.h>
14 #include <Register/Cpuid.h>
15 #include <Register/Msr.h>
16 
17 #include <Library/MtrrLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/CpuLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/DebugLib.h>
22 
23 #define OR_SEED      0x0101010101010101ull
24 #define CLEAR_SEED   0xFFFFFFFFFFFFFFFFull
25 #define MAX_WEIGHT   MAX_UINT8
26 #define SCRATCH_BUFFER_SIZE           (4 * SIZE_4KB)
27 #define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);
28 
29 #define M(x,y) ((x) * VertexCount + (y))
30 #define O(x,y) ((y) * VertexCount + (x))
31 
32 //
33 // Context to save and restore when MTRRs are programmed
34 //
35 typedef struct {
36   UINTN    Cr4;
37   BOOLEAN  InterruptState;
38 } MTRR_CONTEXT;
39 
40 typedef struct {
41   UINT64                 Address;
42   UINT64                 Alignment;
43   UINT64                 Length;
44   MTRR_MEMORY_CACHE_TYPE Type : 7;
45 
46   //
47   // Temprary use for calculating the best MTRR settings.
48   //
49   BOOLEAN                Visited : 1;
50   UINT8                  Weight;
51   UINT16                 Previous;
52 } MTRR_LIB_ADDRESS;
53 
54 //
55 // This table defines the offset, base and length of the fixed MTRRs
56 //
57 CONST FIXED_MTRR  mMtrrLibFixedMtrrTable[] = {
58   {
59     MSR_IA32_MTRR_FIX64K_00000,
60     0,
61     SIZE_64KB
62   },
63   {
64     MSR_IA32_MTRR_FIX16K_80000,
65     0x80000,
66     SIZE_16KB
67   },
68   {
69     MSR_IA32_MTRR_FIX16K_A0000,
70     0xA0000,
71     SIZE_16KB
72   },
73   {
74     MSR_IA32_MTRR_FIX4K_C0000,
75     0xC0000,
76     SIZE_4KB
77   },
78   {
79     MSR_IA32_MTRR_FIX4K_C8000,
80     0xC8000,
81     SIZE_4KB
82   },
83   {
84     MSR_IA32_MTRR_FIX4K_D0000,
85     0xD0000,
86     SIZE_4KB
87   },
88   {
89     MSR_IA32_MTRR_FIX4K_D8000,
90     0xD8000,
91     SIZE_4KB
92   },
93   {
94     MSR_IA32_MTRR_FIX4K_E0000,
95     0xE0000,
96     SIZE_4KB
97   },
98   {
99     MSR_IA32_MTRR_FIX4K_E8000,
100     0xE8000,
101     SIZE_4KB
102   },
103   {
104     MSR_IA32_MTRR_FIX4K_F0000,
105     0xF0000,
106     SIZE_4KB
107   },
108   {
109     MSR_IA32_MTRR_FIX4K_F8000,
110     0xF8000,
111     SIZE_4KB
112   }
113 };
114 
115 //
116 // Lookup table used to print MTRRs
117 //
118 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {
119   "UC",  // CacheUncacheable
120   "WC",  // CacheWriteCombining
121   "R*",  // Invalid
122   "R*",  // Invalid
123   "WT",  // CacheWriteThrough
124   "WP",  // CacheWriteProtected
125   "WB",  // CacheWriteBack
126   "R*"   // Invalid
127 };
128 
129 
130 /**
131   Worker function prints all MTRRs for debugging.
132 
133   If MtrrSetting is not NULL, print MTRR settings from input MTRR
134   settings buffer.
135   If MtrrSetting is NULL, print MTRR settings from MTRRs.
136 
137   @param  MtrrSetting    A buffer holding all MTRRs content.
138 **/
139 VOID
140 MtrrDebugPrintAllMtrrsWorker (
141   IN MTRR_SETTINGS    *MtrrSetting
142   );
143 
144 /**
145   Worker function returns the variable MTRR count for the CPU.
146 
147   @return Variable MTRR count
148 
149 **/
150 UINT32
GetVariableMtrrCountWorker(VOID)151 GetVariableMtrrCountWorker (
152   VOID
153   )
154 {
155   MSR_IA32_MTRRCAP_REGISTER MtrrCap;
156 
157   MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);
158   ASSERT (MtrrCap.Bits.VCNT <= ARRAY_SIZE (((MTRR_VARIABLE_SETTINGS *) 0)->Mtrr));
159   return MtrrCap.Bits.VCNT;
160 }
161 
162 /**
163   Returns the variable MTRR count for the CPU.
164 
165   @return Variable MTRR count
166 
167 **/
168 UINT32
169 EFIAPI
GetVariableMtrrCount(VOID)170 GetVariableMtrrCount (
171   VOID
172   )
173 {
174   if (!IsMtrrSupported ()) {
175     return 0;
176   }
177   return GetVariableMtrrCountWorker ();
178 }
179 
180 /**
181   Worker function returns the firmware usable variable MTRR count for the CPU.
182 
183   @return Firmware usable variable MTRR count
184 
185 **/
186 UINT32
GetFirmwareVariableMtrrCountWorker(VOID)187 GetFirmwareVariableMtrrCountWorker (
188   VOID
189   )
190 {
191   UINT32  VariableMtrrCount;
192   UINT32  ReservedMtrrNumber;
193 
194   VariableMtrrCount = GetVariableMtrrCountWorker ();
195   ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
196   if (VariableMtrrCount < ReservedMtrrNumber) {
197     return 0;
198   }
199 
200   return VariableMtrrCount - ReservedMtrrNumber;
201 }
202 
203 /**
204   Returns the firmware usable variable MTRR count for the CPU.
205 
206   @return Firmware usable variable MTRR count
207 
208 **/
209 UINT32
210 EFIAPI
GetFirmwareVariableMtrrCount(VOID)211 GetFirmwareVariableMtrrCount (
212   VOID
213   )
214 {
215   if (!IsMtrrSupported ()) {
216     return 0;
217   }
218   return GetFirmwareVariableMtrrCountWorker ();
219 }
220 
221 /**
222   Worker function returns the default MTRR cache type for the system.
223 
224   If MtrrSetting is not NULL, returns the default MTRR cache type from input
225   MTRR settings buffer.
226   If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
227 
228   @param[in]  MtrrSetting    A buffer holding all MTRRs content.
229 
230   @return  The default MTRR cache type.
231 
232 **/
233 MTRR_MEMORY_CACHE_TYPE
MtrrGetDefaultMemoryTypeWorker(IN MTRR_SETTINGS * MtrrSetting)234 MtrrGetDefaultMemoryTypeWorker (
235   IN MTRR_SETTINGS      *MtrrSetting
236   )
237 {
238   MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;
239 
240   if (MtrrSetting == NULL) {
241     DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
242   } else {
243     DefType.Uint64 = MtrrSetting->MtrrDefType;
244   }
245 
246   return (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;
247 }
248 
249 
250 /**
251   Returns the default MTRR cache type for the system.
252 
253   @return  The default MTRR cache type.
254 
255 **/
256 MTRR_MEMORY_CACHE_TYPE
257 EFIAPI
MtrrGetDefaultMemoryType(VOID)258 MtrrGetDefaultMemoryType (
259   VOID
260   )
261 {
262   if (!IsMtrrSupported ()) {
263     return CacheUncacheable;
264   }
265   return MtrrGetDefaultMemoryTypeWorker (NULL);
266 }
267 
268 /**
269   Preparation before programming MTRR.
270 
271   This function will do some preparation for programming MTRRs:
272   disable cache, invalid cache and disable MTRR caching functionality
273 
274   @param[out] MtrrContext  Pointer to context to save
275 
276 **/
277 VOID
MtrrLibPreMtrrChange(OUT MTRR_CONTEXT * MtrrContext)278 MtrrLibPreMtrrChange (
279   OUT MTRR_CONTEXT  *MtrrContext
280   )
281 {
282   MSR_IA32_MTRR_DEF_TYPE_REGISTER  DefType;
283   //
284   // Disable interrupts and save current interrupt state
285   //
286   MtrrContext->InterruptState = SaveAndDisableInterrupts();
287 
288   //
289   // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
290   //
291   AsmDisableCache ();
292 
293   //
294   // Save original CR4 value and clear PGE flag (Bit 7)
295   //
296   MtrrContext->Cr4 = AsmReadCr4 ();
297   AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));
298 
299   //
300   // Flush all TLBs
301   //
302   CpuFlushTlb ();
303 
304   //
305   // Disable MTRRs
306   //
307   DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
308   DefType.Bits.E = 0;
309   AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64);
310 }
311 
312 /**
313   Cleaning up after programming MTRRs.
314 
315   This function will do some clean up after programming MTRRs:
316   Flush all TLBs,  re-enable caching, restore CR4.
317 
318   @param[in] MtrrContext  Pointer to context to restore
319 
320 **/
321 VOID
MtrrLibPostMtrrChangeEnableCache(IN MTRR_CONTEXT * MtrrContext)322 MtrrLibPostMtrrChangeEnableCache (
323   IN MTRR_CONTEXT  *MtrrContext
324   )
325 {
326   //
327   // Flush all TLBs
328   //
329   CpuFlushTlb ();
330 
331   //
332   // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
333   //
334   AsmEnableCache ();
335 
336   //
337   // Restore original CR4 value
338   //
339   AsmWriteCr4 (MtrrContext->Cr4);
340 
341   //
342   // Restore original interrupt state
343   //
344   SetInterruptState (MtrrContext->InterruptState);
345 }
346 
347 /**
348   Cleaning up after programming MTRRs.
349 
350   This function will do some clean up after programming MTRRs:
351   enable MTRR caching functionality, and enable cache
352 
353   @param[in] MtrrContext  Pointer to context to restore
354 
355 **/
356 VOID
MtrrLibPostMtrrChange(IN MTRR_CONTEXT * MtrrContext)357 MtrrLibPostMtrrChange (
358   IN MTRR_CONTEXT  *MtrrContext
359   )
360 {
361   MSR_IA32_MTRR_DEF_TYPE_REGISTER  DefType;
362   //
363   // Enable Cache MTRR
364   //
365   DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
366   DefType.Bits.E = 1;
367   DefType.Bits.FE = 1;
368   AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64);
369 
370   MtrrLibPostMtrrChangeEnableCache (MtrrContext);
371 }
372 
373 /**
374   Worker function gets the content in fixed MTRRs
375 
376   @param[out]  FixedSettings  A buffer to hold fixed MTRRs content.
377 
378   @retval The pointer of FixedSettings
379 
380 **/
381 MTRR_FIXED_SETTINGS*
MtrrGetFixedMtrrWorker(OUT MTRR_FIXED_SETTINGS * FixedSettings)382 MtrrGetFixedMtrrWorker (
383   OUT MTRR_FIXED_SETTINGS         *FixedSettings
384   )
385 {
386   UINT32  Index;
387 
388   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
389       FixedSettings->Mtrr[Index] =
390         AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
391   }
392 
393   return FixedSettings;
394 }
395 
396 
397 /**
398   This function gets the content in fixed MTRRs
399 
400   @param[out]  FixedSettings  A buffer to hold fixed MTRRs content.
401 
402   @retval The pointer of FixedSettings
403 
404 **/
405 MTRR_FIXED_SETTINGS*
406 EFIAPI
MtrrGetFixedMtrr(OUT MTRR_FIXED_SETTINGS * FixedSettings)407 MtrrGetFixedMtrr (
408   OUT MTRR_FIXED_SETTINGS         *FixedSettings
409   )
410 {
411   if (!IsMtrrSupported ()) {
412     return FixedSettings;
413   }
414 
415   return MtrrGetFixedMtrrWorker (FixedSettings);
416 }
417 
418 
419 /**
420   Worker function will get the raw value in variable MTRRs
421 
422   If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
423   MTRR settings buffer.
424   If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
425 
426   @param[in]  MtrrSetting        A buffer holding all MTRRs content.
427   @param[in]  VariableMtrrCount  Number of variable MTRRs.
428   @param[out] VariableSettings   A buffer to hold variable MTRRs content.
429 
430   @return The VariableSettings input pointer
431 
432 **/
433 MTRR_VARIABLE_SETTINGS*
MtrrGetVariableMtrrWorker(IN MTRR_SETTINGS * MtrrSetting,IN UINT32 VariableMtrrCount,OUT MTRR_VARIABLE_SETTINGS * VariableSettings)434 MtrrGetVariableMtrrWorker (
435   IN  MTRR_SETTINGS           *MtrrSetting,
436   IN  UINT32                  VariableMtrrCount,
437   OUT MTRR_VARIABLE_SETTINGS  *VariableSettings
438   )
439 {
440   UINT32  Index;
441 
442   ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->Mtrr));
443 
444   for (Index = 0; Index < VariableMtrrCount; Index++) {
445     if (MtrrSetting == NULL) {
446       VariableSettings->Mtrr[Index].Base =
447         AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1));
448       VariableSettings->Mtrr[Index].Mask =
449         AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1));
450     } else {
451       VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;
452       VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;
453     }
454   }
455 
456   return  VariableSettings;
457 }
458 
459 /**
460   This function will get the raw value in variable MTRRs
461 
462   @param[out]  VariableSettings   A buffer to hold variable MTRRs content.
463 
464   @return The VariableSettings input pointer
465 
466 **/
467 MTRR_VARIABLE_SETTINGS*
468 EFIAPI
MtrrGetVariableMtrr(OUT MTRR_VARIABLE_SETTINGS * VariableSettings)469 MtrrGetVariableMtrr (
470   OUT MTRR_VARIABLE_SETTINGS         *VariableSettings
471   )
472 {
473   if (!IsMtrrSupported ()) {
474     return VariableSettings;
475   }
476 
477   return MtrrGetVariableMtrrWorker (
478            NULL,
479            GetVariableMtrrCountWorker (),
480            VariableSettings
481            );
482 }
483 
484 /**
485   Programs fixed MTRRs registers.
486 
487   @param[in]      Type             The memory type to set.
488   @param[in, out] Base             The base address of memory range.
489   @param[in, out] Length           The length of memory range.
490   @param[in, out] LastMsrIndex     On input, the last index of the fixed MTRR MSR to program.
491                                    On return, the current index of the fixed MTRR MSR to program.
492   @param[out]     ClearMask        The bits to clear in the fixed MTRR MSR.
493   @param[out]     OrMask           The bits to set in the fixed MTRR MSR.
494 
495   @retval RETURN_SUCCESS      The cache type was updated successfully
496   @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid
497                               for the fixed MTRRs.
498 
499 **/
500 RETURN_STATUS
MtrrLibProgramFixedMtrr(IN MTRR_MEMORY_CACHE_TYPE Type,IN OUT UINT64 * Base,IN OUT UINT64 * Length,IN OUT UINT32 * LastMsrIndex,OUT UINT64 * ClearMask,OUT UINT64 * OrMask)501 MtrrLibProgramFixedMtrr (
502   IN     MTRR_MEMORY_CACHE_TYPE  Type,
503   IN OUT UINT64                  *Base,
504   IN OUT UINT64                  *Length,
505   IN OUT UINT32                  *LastMsrIndex,
506   OUT    UINT64                  *ClearMask,
507   OUT    UINT64                  *OrMask
508   )
509 {
510   UINT32  MsrIndex;
511   UINT32  LeftByteShift;
512   UINT32  RightByteShift;
513   UINT64  SubLength;
514 
515   //
516   // Find the fixed MTRR index to be programmed
517   //
518   for (MsrIndex = *LastMsrIndex + 1; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {
519     if ((*Base >= mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) &&
520         (*Base <
521             (
522               mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress +
523               (8 * mMtrrLibFixedMtrrTable[MsrIndex].Length)
524             )
525           )
526         ) {
527       break;
528     }
529   }
530 
531   ASSERT (MsrIndex != ARRAY_SIZE (mMtrrLibFixedMtrrTable));
532 
533   //
534   // Find the begin offset in fixed MTRR and calculate byte offset of left shift
535   //
536   if ((((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) % mMtrrLibFixedMtrrTable[MsrIndex].Length) != 0) {
537     //
538     // Base address should be aligned to the begin of a certain Fixed MTRR range.
539     //
540     return RETURN_UNSUPPORTED;
541   }
542   LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) / mMtrrLibFixedMtrrTable[MsrIndex].Length;
543   ASSERT (LeftByteShift < 8);
544 
545   //
546   // Find the end offset in fixed MTRR and calculate byte offset of right shift
547   //
548   SubLength = mMtrrLibFixedMtrrTable[MsrIndex].Length * (8 - LeftByteShift);
549   if (*Length >= SubLength) {
550     RightByteShift = 0;
551   } else {
552     if (((UINT32)(*Length) % mMtrrLibFixedMtrrTable[MsrIndex].Length) != 0) {
553       //
554       // Length should be aligned to the end of a certain Fixed MTRR range.
555       //
556       return RETURN_UNSUPPORTED;
557     }
558     RightByteShift = 8 - LeftByteShift - (UINT32)(*Length) / mMtrrLibFixedMtrrTable[MsrIndex].Length;
559     //
560     // Update SubLength by actual length
561     //
562     SubLength = *Length;
563   }
564 
565   *ClearMask = CLEAR_SEED;
566   *OrMask    = MultU64x32 (OR_SEED, (UINT32) Type);
567 
568   if (LeftByteShift != 0) {
569     //
570     // Clear the low bits by LeftByteShift
571     //
572     *ClearMask &= LShiftU64 (*ClearMask, LeftByteShift * 8);
573     *OrMask    &= LShiftU64 (*OrMask,    LeftByteShift * 8);
574   }
575 
576   if (RightByteShift != 0) {
577     //
578     // Clear the high bits by RightByteShift
579     //
580     *ClearMask &= RShiftU64 (*ClearMask, RightByteShift * 8);
581     *OrMask    &= RShiftU64 (*OrMask,    RightByteShift * 8);
582   }
583 
584   *Length -= SubLength;
585   *Base   += SubLength;
586 
587   *LastMsrIndex    = MsrIndex;
588 
589   return RETURN_SUCCESS;
590 }
591 
592 
593 /**
594   Worker function gets the attribute of variable MTRRs.
595 
596   This function shadows the content of variable MTRRs into an
597   internal array: VariableMtrr.
598 
599   @param[in]   VariableSettings      The variable MTRR values to shadow
600   @param[in]   VariableMtrrCount     The number of variable MTRRs
601   @param[in]   MtrrValidBitsMask     The mask for the valid bit of the MTRR
602   @param[in]   MtrrValidAddressMask  The valid address mask for MTRR
603   @param[out]  VariableMtrr          The array to shadow variable MTRRs content
604 
605   @return      Number of MTRRs which has been used.
606 
607 **/
608 UINT32
MtrrGetMemoryAttributeInVariableMtrrWorker(IN MTRR_VARIABLE_SETTINGS * VariableSettings,IN UINTN VariableMtrrCount,IN UINT64 MtrrValidBitsMask,IN UINT64 MtrrValidAddressMask,OUT VARIABLE_MTRR * VariableMtrr)609 MtrrGetMemoryAttributeInVariableMtrrWorker (
610   IN  MTRR_VARIABLE_SETTINGS  *VariableSettings,
611   IN  UINTN                   VariableMtrrCount,
612   IN  UINT64                  MtrrValidBitsMask,
613   IN  UINT64                  MtrrValidAddressMask,
614   OUT VARIABLE_MTRR           *VariableMtrr
615   )
616 {
617   UINTN   Index;
618   UINT32  UsedMtrr;
619 
620   ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * ARRAY_SIZE (VariableSettings->Mtrr));
621   for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) {
622     if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {
623       VariableMtrr[Index].Msr         = (UINT32)Index;
624       VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);
625       VariableMtrr[Index].Length      =
626         ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;
627       VariableMtrr[Index].Type        = (VariableSettings->Mtrr[Index].Base & 0x0ff);
628       VariableMtrr[Index].Valid       = TRUE;
629       VariableMtrr[Index].Used        = TRUE;
630       UsedMtrr++;
631     }
632   }
633   return UsedMtrr;
634 }
635 
636 /**
637   Convert variable MTRRs to a RAW MTRR_MEMORY_RANGE array.
638   One MTRR_MEMORY_RANGE element is created for each MTRR setting.
639   The routine doesn't remove the overlap or combine the near-by region.
640 
641   @param[in]   VariableSettings      The variable MTRR values to shadow
642   @param[in]   VariableMtrrCount     The number of variable MTRRs
643   @param[in]   MtrrValidBitsMask     The mask for the valid bit of the MTRR
644   @param[in]   MtrrValidAddressMask  The valid address mask for MTRR
645   @param[out]  VariableMtrr          The array to shadow variable MTRRs content
646 
647   @return      Number of MTRRs which has been used.
648 
649 **/
650 UINT32
MtrrLibGetRawVariableRanges(IN MTRR_VARIABLE_SETTINGS * VariableSettings,IN UINTN VariableMtrrCount,IN UINT64 MtrrValidBitsMask,IN UINT64 MtrrValidAddressMask,OUT MTRR_MEMORY_RANGE * VariableMtrr)651 MtrrLibGetRawVariableRanges (
652   IN  MTRR_VARIABLE_SETTINGS  *VariableSettings,
653   IN  UINTN                   VariableMtrrCount,
654   IN  UINT64                  MtrrValidBitsMask,
655   IN  UINT64                  MtrrValidAddressMask,
656   OUT MTRR_MEMORY_RANGE       *VariableMtrr
657   )
658 {
659   UINTN   Index;
660   UINT32  UsedMtrr;
661 
662   ZeroMem (VariableMtrr, sizeof (MTRR_MEMORY_RANGE) * ARRAY_SIZE (VariableSettings->Mtrr));
663   for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) {
664     if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {
665       VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);
666       VariableMtrr[Index].Length      =
667         ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;
668       VariableMtrr[Index].Type        = (MTRR_MEMORY_CACHE_TYPE)(VariableSettings->Mtrr[Index].Base & 0x0ff);
669       UsedMtrr++;
670     }
671   }
672   return UsedMtrr;
673 }
674 
675 /**
676   Gets the attribute of variable MTRRs.
677 
678   This function shadows the content of variable MTRRs into an
679   internal array: VariableMtrr.
680 
681   @param[in]   MtrrValidBitsMask     The mask for the valid bit of the MTRR
682   @param[in]   MtrrValidAddressMask  The valid address mask for MTRR
683   @param[out]  VariableMtrr          The array to shadow variable MTRRs content
684 
685   @return                       The return value of this parameter indicates the
686                                 number of MTRRs which has been used.
687 
688 **/
689 UINT32
690 EFIAPI
MtrrGetMemoryAttributeInVariableMtrr(IN UINT64 MtrrValidBitsMask,IN UINT64 MtrrValidAddressMask,OUT VARIABLE_MTRR * VariableMtrr)691 MtrrGetMemoryAttributeInVariableMtrr (
692   IN  UINT64                    MtrrValidBitsMask,
693   IN  UINT64                    MtrrValidAddressMask,
694   OUT VARIABLE_MTRR             *VariableMtrr
695   )
696 {
697   MTRR_VARIABLE_SETTINGS  VariableSettings;
698 
699   if (!IsMtrrSupported ()) {
700     return 0;
701   }
702 
703   MtrrGetVariableMtrrWorker (
704     NULL,
705     GetVariableMtrrCountWorker (),
706     &VariableSettings
707     );
708 
709   return MtrrGetMemoryAttributeInVariableMtrrWorker (
710            &VariableSettings,
711            GetFirmwareVariableMtrrCountWorker (),
712            MtrrValidBitsMask,
713            MtrrValidAddressMask,
714            VariableMtrr
715            );
716 }
717 
718 /**
719   Return the biggest alignment (lowest set bit) of address.
720   The function is equivalent to: 1 << LowBitSet64 (Address).
721 
722   @param Address    The address to return the alignment.
723   @param Alignment0 The alignment to return when Address is 0.
724 
725   @return The least alignment of the Address.
726 **/
727 UINT64
MtrrLibBiggestAlignment(UINT64 Address,UINT64 Alignment0)728 MtrrLibBiggestAlignment (
729   UINT64    Address,
730   UINT64    Alignment0
731 )
732 {
733   if (Address == 0) {
734     return Alignment0;
735   }
736 
737   return Address & ((~Address) + 1);
738 }
739 
740 /**
741   Return whether the left MTRR type precedes the right MTRR type.
742 
743   The MTRR type precedence rules are:
744     1. UC precedes any other type
745     2. WT precedes WB
746   For further details, please refer the IA32 Software Developer's Manual,
747   Volume 3, Section "MTRR Precedences".
748 
749   @param Left  The left MTRR type.
750   @param Right The right MTRR type.
751 
752   @retval TRUE  Left precedes Right.
753   @retval FALSE Left doesn't precede Right.
754 **/
755 BOOLEAN
MtrrLibTypeLeftPrecedeRight(IN MTRR_MEMORY_CACHE_TYPE Left,IN MTRR_MEMORY_CACHE_TYPE Right)756 MtrrLibTypeLeftPrecedeRight (
757   IN MTRR_MEMORY_CACHE_TYPE  Left,
758   IN MTRR_MEMORY_CACHE_TYPE  Right
759 )
760 {
761   return (BOOLEAN) (Left == CacheUncacheable || (Left == CacheWriteThrough && Right == CacheWriteBack));
762 }
763 
764 /**
765   Initializes the valid bits mask and valid address mask for MTRRs.
766 
767   This function initializes the valid bits mask and valid address mask for MTRRs.
768 
769   @param[out]  MtrrValidBitsMask     The mask for the valid bit of the MTRR
770   @param[out]  MtrrValidAddressMask  The valid address mask for the MTRR
771 
772 **/
773 VOID
MtrrLibInitializeMtrrMask(OUT UINT64 * MtrrValidBitsMask,OUT UINT64 * MtrrValidAddressMask)774 MtrrLibInitializeMtrrMask (
775   OUT UINT64 *MtrrValidBitsMask,
776   OUT UINT64 *MtrrValidAddressMask
777   )
778 {
779   UINT32                          MaxExtendedFunction;
780   CPUID_VIR_PHY_ADDRESS_SIZE_EAX  VirPhyAddressSize;
781 
782 
783   AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);
784 
785   if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {
786     AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);
787   } else {
788     VirPhyAddressSize.Bits.PhysicalAddressBits = 36;
789   }
790 
791   *MtrrValidBitsMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1;
792   *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
793 }
794 
795 
796 /**
797   Determines the real attribute of a memory range.
798 
799   This function is to arbitrate the real attribute of the memory when
800   there are 2 MTRRs covers the same memory range. For further details,
801   please refer the IA32 Software Developer's Manual, Volume 3,
802   Section "MTRR Precedences".
803 
804   @param[in]  MtrrType1    The first kind of Memory type
805   @param[in]  MtrrType2    The second kind of memory type
806 
807 **/
808 MTRR_MEMORY_CACHE_TYPE
MtrrLibPrecedence(IN MTRR_MEMORY_CACHE_TYPE MtrrType1,IN MTRR_MEMORY_CACHE_TYPE MtrrType2)809 MtrrLibPrecedence (
810   IN MTRR_MEMORY_CACHE_TYPE    MtrrType1,
811   IN MTRR_MEMORY_CACHE_TYPE    MtrrType2
812   )
813 {
814   if (MtrrType1 == MtrrType2) {
815     return MtrrType1;
816   }
817 
818   ASSERT (
819     MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2) ||
820     MtrrLibTypeLeftPrecedeRight (MtrrType2, MtrrType1)
821   );
822 
823   if (MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2)) {
824     return MtrrType1;
825   } else {
826     return MtrrType2;
827   }
828 }
829 
830 /**
831   Worker function will get the memory cache type of the specific address.
832 
833   If MtrrSetting is not NULL, gets the memory cache type from input
834   MTRR settings buffer.
835   If MtrrSetting is NULL, gets the memory cache type from MTRRs.
836 
837   @param[in]  MtrrSetting        A buffer holding all MTRRs content.
838   @param[in]  Address            The specific address
839 
840   @return Memory cache type of the specific address
841 
842 **/
843 MTRR_MEMORY_CACHE_TYPE
MtrrGetMemoryAttributeByAddressWorker(IN MTRR_SETTINGS * MtrrSetting,IN PHYSICAL_ADDRESS Address)844 MtrrGetMemoryAttributeByAddressWorker (
845   IN MTRR_SETTINGS      *MtrrSetting,
846   IN PHYSICAL_ADDRESS   Address
847   )
848 {
849   MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;
850   UINT64                          FixedMtrr;
851   UINTN                           Index;
852   UINTN                           SubIndex;
853   MTRR_MEMORY_CACHE_TYPE          MtrrType;
854   MTRR_MEMORY_RANGE               VariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
855   UINT64                          MtrrValidBitsMask;
856   UINT64                          MtrrValidAddressMask;
857   UINT32                          VariableMtrrCount;
858   MTRR_VARIABLE_SETTINGS          VariableSettings;
859 
860   //
861   // Check if MTRR is enabled, if not, return UC as attribute
862   //
863   if (MtrrSetting == NULL) {
864     DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
865   } else {
866     DefType.Uint64 = MtrrSetting->MtrrDefType;
867   }
868 
869   if (DefType.Bits.E == 0) {
870     return CacheUncacheable;
871   }
872 
873   //
874   // If address is less than 1M, then try to go through the fixed MTRR
875   //
876   if (Address < BASE_1MB) {
877     if (DefType.Bits.FE != 0) {
878       //
879       // Go through the fixed MTRR
880       //
881       for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
882         if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&
883             Address < mMtrrLibFixedMtrrTable[Index].BaseAddress +
884             (mMtrrLibFixedMtrrTable[Index].Length * 8)) {
885           SubIndex =
886             ((UINTN) Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /
887             mMtrrLibFixedMtrrTable[Index].Length;
888           if (MtrrSetting == NULL) {
889             FixedMtrr = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
890           } else {
891             FixedMtrr = MtrrSetting->Fixed.Mtrr[Index];
892           }
893           return (MTRR_MEMORY_CACHE_TYPE) (RShiftU64 (FixedMtrr, SubIndex * 8) & 0xFF);
894         }
895       }
896     }
897   }
898 
899   VariableMtrrCount = GetVariableMtrrCountWorker ();
900   ASSERT (VariableMtrrCount <= ARRAY_SIZE (MtrrSetting->Variables.Mtrr));
901   MtrrGetVariableMtrrWorker (MtrrSetting, VariableMtrrCount, &VariableSettings);
902 
903   MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
904   MtrrLibGetRawVariableRanges (
905     &VariableSettings,
906     VariableMtrrCount,
907     MtrrValidBitsMask,
908     MtrrValidAddressMask,
909     VariableMtrr
910   );
911 
912   //
913   // Go through the variable MTRR
914   //
915   MtrrType = CacheInvalid;
916   for (Index = 0; Index < VariableMtrrCount; Index++) {
917     if (VariableMtrr[Index].Length != 0) {
918       if (Address >= VariableMtrr[Index].BaseAddress &&
919           Address < VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length) {
920         if (MtrrType == CacheInvalid) {
921           MtrrType = (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type;
922         } else {
923           MtrrType = MtrrLibPrecedence (MtrrType, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type);
924         }
925       }
926     }
927   }
928 
929   //
930   // If there is no MTRR which covers the Address, use the default MTRR type.
931   //
932   if (MtrrType == CacheInvalid) {
933     MtrrType = (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;
934   }
935 
936   return MtrrType;
937 }
938 
939 
940 /**
941   This function will get the memory cache type of the specific address.
942 
943   This function is mainly for debug purpose.
944 
945   @param[in]  Address   The specific address
946 
947   @return Memory cache type of the specific address
948 
949 **/
950 MTRR_MEMORY_CACHE_TYPE
951 EFIAPI
MtrrGetMemoryAttribute(IN PHYSICAL_ADDRESS Address)952 MtrrGetMemoryAttribute (
953   IN PHYSICAL_ADDRESS   Address
954   )
955 {
956   if (!IsMtrrSupported ()) {
957     return CacheUncacheable;
958   }
959 
960   return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);
961 }
962 
963 /**
964   Update the Ranges array to change the specified range identified by
965   BaseAddress and Length to Type.
966 
967   @param Ranges      Array holding memory type settings for all memory regions.
968   @param Capacity    The maximum count of memory ranges the array can hold.
969   @param Count       Return the new memory range count in the array.
970   @param BaseAddress The base address of the memory range to change type.
971   @param Length      The length of the memory range to change type.
972   @param Type        The new type of the specified memory range.
973 
974   @retval RETURN_SUCCESS          The type of the specified memory range is
975                                   changed successfully.
976   @retval RETURN_ALREADY_STARTED  The type of the specified memory range equals
977                                   to the desired type.
978   @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory
979                                   range exceeds capacity.
980 **/
981 RETURN_STATUS
MtrrLibSetMemoryType(IN MTRR_MEMORY_RANGE * Ranges,IN UINTN Capacity,IN OUT UINTN * Count,IN UINT64 BaseAddress,IN UINT64 Length,IN MTRR_MEMORY_CACHE_TYPE Type)982 MtrrLibSetMemoryType (
983   IN MTRR_MEMORY_RANGE             *Ranges,
984   IN UINTN                         Capacity,
985   IN OUT UINTN                     *Count,
986   IN UINT64                        BaseAddress,
987   IN UINT64                        Length,
988   IN MTRR_MEMORY_CACHE_TYPE        Type
989   )
990 {
991   UINTN                            Index;
992   UINT64                           Limit;
993   UINT64                           LengthLeft;
994   UINT64                           LengthRight;
995   UINTN                            StartIndex;
996   UINTN                            EndIndex;
997   UINTN                            DeltaCount;
998 
999   LengthRight = 0;
1000   LengthLeft  = 0;
1001   Limit = BaseAddress + Length;
1002   StartIndex = *Count;
1003   EndIndex = *Count;
1004   for (Index = 0; Index < *Count; Index++) {
1005     if ((StartIndex == *Count) &&
1006         (Ranges[Index].BaseAddress <= BaseAddress) &&
1007         (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)) {
1008       StartIndex = Index;
1009       LengthLeft = BaseAddress - Ranges[Index].BaseAddress;
1010     }
1011 
1012     if ((EndIndex == *Count) &&
1013         (Ranges[Index].BaseAddress < Limit) &&
1014         (Limit <= Ranges[Index].BaseAddress + Ranges[Index].Length)) {
1015       EndIndex = Index;
1016       LengthRight = Ranges[Index].BaseAddress + Ranges[Index].Length - Limit;
1017       break;
1018     }
1019   }
1020 
1021   ASSERT (StartIndex != *Count && EndIndex != *Count);
1022   if (StartIndex == EndIndex && Ranges[StartIndex].Type == Type) {
1023     return RETURN_ALREADY_STARTED;
1024   }
1025 
1026   //
1027   // The type change may cause merging with previous range or next range.
1028   // Update the StartIndex, EndIndex, BaseAddress, Length so that following
1029   // logic doesn't need to consider merging.
1030   //
1031   if (StartIndex != 0) {
1032     if (LengthLeft == 0 && Ranges[StartIndex - 1].Type == Type) {
1033       StartIndex--;
1034       Length += Ranges[StartIndex].Length;
1035       BaseAddress -= Ranges[StartIndex].Length;
1036     }
1037   }
1038   if (EndIndex != (*Count) - 1) {
1039     if (LengthRight == 0 && Ranges[EndIndex + 1].Type == Type) {
1040       EndIndex++;
1041       Length += Ranges[EndIndex].Length;
1042     }
1043   }
1044 
1045   //
1046   // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount  Count (Count = 4)
1047   //   |++++++++++++++++++|    0          3         1=3-0-2    3
1048   //   |+++++++|               0          1        -1=1-0-2    5
1049   //   |+|                     0          0        -2=0-0-2    6
1050   // |+++|                     0          0        -1=0-0-2+1  5
1051   //
1052   //
1053   DeltaCount = EndIndex - StartIndex - 2;
1054   if (LengthLeft == 0) {
1055     DeltaCount++;
1056   }
1057   if (LengthRight == 0) {
1058     DeltaCount++;
1059   }
1060   if (*Count - DeltaCount > Capacity) {
1061     return RETURN_OUT_OF_RESOURCES;
1062   }
1063 
1064   //
1065   // Reserve (-DeltaCount) space
1066   //
1067   CopyMem (&Ranges[EndIndex + 1 - DeltaCount], &Ranges[EndIndex + 1], (*Count - EndIndex - 1) * sizeof (Ranges[0]));
1068   *Count -= DeltaCount;
1069 
1070   if (LengthLeft != 0) {
1071     Ranges[StartIndex].Length = LengthLeft;
1072     StartIndex++;
1073   }
1074   if (LengthRight != 0) {
1075     Ranges[EndIndex - DeltaCount].BaseAddress = BaseAddress + Length;
1076     Ranges[EndIndex - DeltaCount].Length = LengthRight;
1077     Ranges[EndIndex - DeltaCount].Type = Ranges[EndIndex].Type;
1078   }
1079   Ranges[StartIndex].BaseAddress = BaseAddress;
1080   Ranges[StartIndex].Length = Length;
1081   Ranges[StartIndex].Type = Type;
1082   return RETURN_SUCCESS;
1083 }
1084 
1085 /**
1086   Return the number of memory types in range [BaseAddress, BaseAddress + Length).
1087 
1088   @param Ranges      Array holding memory type settings for all memory regions.
1089   @param RangeCount  The count of memory ranges the array holds.
1090   @param BaseAddress Base address.
1091   @param Length      Length.
1092   @param Types       Return bit mask to indicate all memory types in the specified range.
1093 
1094   @retval  Number of memory types.
1095 **/
1096 UINT8
MtrrLibGetNumberOfTypes(IN CONST MTRR_MEMORY_RANGE * Ranges,IN UINTN RangeCount,IN UINT64 BaseAddress,IN UINT64 Length,IN OUT UINT8 * Types OPTIONAL)1097 MtrrLibGetNumberOfTypes (
1098   IN CONST MTRR_MEMORY_RANGE     *Ranges,
1099   IN UINTN                       RangeCount,
1100   IN UINT64                      BaseAddress,
1101   IN UINT64                      Length,
1102   IN OUT UINT8                   *Types  OPTIONAL
1103   )
1104 {
1105   UINTN                          Index;
1106   UINT8                          TypeCount;
1107   UINT8                          LocalTypes;
1108 
1109   TypeCount = 0;
1110   LocalTypes = 0;
1111   for (Index = 0; Index < RangeCount; Index++) {
1112     if ((Ranges[Index].BaseAddress <= BaseAddress) &&
1113         (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)
1114         ) {
1115       if ((LocalTypes & (1 << Ranges[Index].Type)) == 0) {
1116         LocalTypes |= (UINT8)(1 << Ranges[Index].Type);
1117         TypeCount++;
1118       }
1119 
1120       if (BaseAddress + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) {
1121         Length -= Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress;
1122         BaseAddress = Ranges[Index].BaseAddress + Ranges[Index].Length;
1123       } else {
1124         break;
1125       }
1126     }
1127   }
1128 
1129   if (Types != NULL) {
1130     *Types = LocalTypes;
1131   }
1132   return TypeCount;
1133 }
1134 
1135 /**
1136   Calculate the least MTRR number from vertex Start to Stop and update
1137   the Previous of all vertices from Start to Stop is updated to reflect
1138   how the memory range is covered by MTRR.
1139 
1140   @param VertexCount     The count of vertices in the graph.
1141   @param Vertices        Array holding all vertices.
1142   @param Weight          2-dimention array holding weights between vertices.
1143   @param Start           Start vertex.
1144   @param Stop            Stop vertex.
1145   @param IncludeOptional TRUE to count the optional weight.
1146 **/
1147 VOID
MtrrLibCalculateLeastMtrrs(IN UINT16 VertexCount,IN MTRR_LIB_ADDRESS * Vertices,IN OUT CONST UINT8 * Weight,IN UINT16 Start,IN UINT16 Stop,IN BOOLEAN IncludeOptional)1148 MtrrLibCalculateLeastMtrrs (
1149   IN UINT16                      VertexCount,
1150   IN MTRR_LIB_ADDRESS            *Vertices,
1151   IN OUT CONST UINT8             *Weight,
1152   IN UINT16                      Start,
1153   IN UINT16                      Stop,
1154   IN BOOLEAN                     IncludeOptional
1155   )
1156 {
1157   UINT16                         Index;
1158   UINT8                          MinWeight;
1159   UINT16                         MinI;
1160   UINT8                          Mandatory;
1161   UINT8                          Optional;
1162 
1163   for (Index = Start; Index <= Stop; Index++) {
1164     Vertices[Index].Visited = FALSE;
1165     Mandatory = Weight[M(Start,Index)];
1166     Vertices[Index].Weight = Mandatory;
1167     if (Mandatory != MAX_WEIGHT) {
1168       Optional = IncludeOptional ? Weight[O(Start, Index)] : 0;
1169       Vertices[Index].Weight += Optional;
1170       ASSERT (Vertices[Index].Weight >= Optional);
1171     }
1172   }
1173 
1174   MinI = Start;
1175   MinWeight = 0;
1176   while (!Vertices[Stop].Visited) {
1177     //
1178     // Update the weight from the shortest vertex to other unvisited vertices
1179     //
1180     for (Index = Start + 1; Index <= Stop; Index++) {
1181       if (!Vertices[Index].Visited) {
1182         Mandatory = Weight[M(MinI, Index)];
1183         if (Mandatory != MAX_WEIGHT) {
1184           Optional = IncludeOptional ? Weight[O(MinI, Index)] : 0;
1185           if (MinWeight + Mandatory + Optional <= Vertices[Index].Weight) {
1186             Vertices[Index].Weight   = MinWeight + Mandatory + Optional;
1187             Vertices[Index].Previous = MinI; // Previous is Start based.
1188           }
1189         }
1190       }
1191     }
1192 
1193     //
1194     // Find the shortest vertex from Start
1195     //
1196     MinI      = VertexCount;
1197     MinWeight = MAX_WEIGHT;
1198     for (Index = Start + 1; Index <= Stop; Index++) {
1199       if (!Vertices[Index].Visited && MinWeight > Vertices[Index].Weight) {
1200         MinI      = Index;
1201         MinWeight = Vertices[Index].Weight;
1202       }
1203     }
1204 
1205     //
1206     // Mark the shortest vertex from Start as visited
1207     //
1208     Vertices[MinI].Visited = TRUE;
1209   }
1210 }
1211 
1212 /**
1213   Append the MTRR setting to MTRR setting array.
1214 
1215   @param Mtrrs        Array holding all MTRR settings.
1216   @param MtrrCapacity Capacity of the MTRR array.
1217   @param MtrrCount    The count of MTRR settings in array.
1218   @param BaseAddress  Base address.
1219   @param Length       Length.
1220   @param Type         Memory type.
1221 
1222   @retval RETURN_SUCCESS          MTRR setting is appended to array.
1223   @retval RETURN_OUT_OF_RESOURCES Array is full.
1224 **/
1225 RETURN_STATUS
MtrrLibAppendVariableMtrr(IN OUT MTRR_MEMORY_RANGE * Mtrrs,IN UINT32 MtrrCapacity,IN OUT UINT32 * MtrrCount,IN UINT64 BaseAddress,IN UINT64 Length,IN MTRR_MEMORY_CACHE_TYPE Type)1226 MtrrLibAppendVariableMtrr (
1227   IN OUT MTRR_MEMORY_RANGE       *Mtrrs,
1228   IN     UINT32                  MtrrCapacity,
1229   IN OUT UINT32                  *MtrrCount,
1230   IN     UINT64                  BaseAddress,
1231   IN     UINT64                  Length,
1232   IN     MTRR_MEMORY_CACHE_TYPE  Type
1233   )
1234 {
1235   if (*MtrrCount == MtrrCapacity) {
1236     return RETURN_OUT_OF_RESOURCES;
1237   }
1238 
1239   Mtrrs[*MtrrCount].BaseAddress = BaseAddress;
1240   Mtrrs[*MtrrCount].Length      = Length;
1241   Mtrrs[*MtrrCount].Type        = Type;
1242   (*MtrrCount)++;
1243   return RETURN_SUCCESS;
1244 }
1245 
1246 /**
1247   Return the memory type that has the least precedence.
1248 
1249   @param TypeBits  Bit mask of memory type.
1250 
1251   @retval  Memory type that has the least precedence.
1252 **/
1253 MTRR_MEMORY_CACHE_TYPE
MtrrLibLowestType(IN UINT8 TypeBits)1254 MtrrLibLowestType (
1255   IN      UINT8                    TypeBits
1256 )
1257 {
1258   INT8                             Type;
1259 
1260   ASSERT (TypeBits != 0);
1261   for (Type = 7; (INT8)TypeBits > 0; Type--, TypeBits <<= 1);
1262   return (MTRR_MEMORY_CACHE_TYPE)Type;
1263 }
1264 
1265 /**
1266   Return TRUE when the Operand is exactly power of 2.
1267 
1268   @retval TRUE  Operand is exactly power of 2.
1269   @retval FALSE Operand is not power of 2.
1270 **/
1271 BOOLEAN
MtrrLibIsPowerOfTwo(IN UINT64 Operand)1272 MtrrLibIsPowerOfTwo (
1273   IN     UINT64                  Operand
1274 )
1275 {
1276   ASSERT (Operand != 0);
1277   return (BOOLEAN) ((Operand & (Operand - 1)) == 0);
1278 }
1279 
1280 /**
1281   Calculate the subtractive path from vertex Start to Stop.
1282 
1283   @param DefaultType  Default memory type.
1284   @param A0           Alignment to use when base address is 0.
1285   @param Ranges       Array holding memory type settings for all memory regions.
1286   @param RangeCount   The count of memory ranges the array holds.
1287   @param VertexCount  The count of vertices in the graph.
1288   @param Vertices     Array holding all vertices.
1289   @param Weight       2-dimention array holding weights between vertices.
1290   @param Start        Start vertex.
1291   @param Stop         Stop vertex.
1292   @param Types        Type bit mask of memory range from Start to Stop.
1293   @param TypeCount    Number of different memory types from Start to Stop.
1294   @param Mtrrs        Array holding all MTRR settings.
1295   @param MtrrCapacity Capacity of the MTRR array.
1296   @param MtrrCount    The count of MTRR settings in array.
1297 
1298   @retval RETURN_SUCCESS          The subtractive path is calculated successfully.
1299   @retval RETURN_OUT_OF_RESOURCES The MTRR setting array is full.
1300 
1301 **/
1302 RETURN_STATUS
MtrrLibCalculateSubtractivePath(IN MTRR_MEMORY_CACHE_TYPE DefaultType,IN UINT64 A0,IN CONST MTRR_MEMORY_RANGE * Ranges,IN UINTN RangeCount,IN UINT16 VertexCount,IN MTRR_LIB_ADDRESS * Vertices,IN OUT UINT8 * Weight,IN UINT16 Start,IN UINT16 Stop,IN UINT8 Types,IN UINT8 TypeCount,IN OUT MTRR_MEMORY_RANGE * Mtrrs,OPTIONAL IN UINT32 MtrrCapacity,OPTIONAL IN OUT UINT32 * MtrrCount OPTIONAL)1303 MtrrLibCalculateSubtractivePath (
1304   IN MTRR_MEMORY_CACHE_TYPE      DefaultType,
1305   IN UINT64                      A0,
1306   IN CONST MTRR_MEMORY_RANGE     *Ranges,
1307   IN UINTN                       RangeCount,
1308   IN UINT16                      VertexCount,
1309   IN MTRR_LIB_ADDRESS            *Vertices,
1310   IN OUT UINT8                   *Weight,
1311   IN UINT16                      Start,
1312   IN UINT16                      Stop,
1313   IN UINT8                       Types,
1314   IN UINT8                       TypeCount,
1315   IN OUT MTRR_MEMORY_RANGE       *Mtrrs,       OPTIONAL
1316   IN UINT32                      MtrrCapacity, OPTIONAL
1317   IN OUT UINT32                  *MtrrCount    OPTIONAL
1318   )
1319 {
1320   RETURN_STATUS                  Status;
1321   UINT64                         Base;
1322   UINT64                         Length;
1323   UINT8                          PrecedentTypes;
1324   UINTN                          Index;
1325   UINT64                         HBase;
1326   UINT64                         HLength;
1327   UINT64                         SubLength;
1328   UINT16                         SubStart;
1329   UINT16                         SubStop;
1330   UINT16                         Cur;
1331   UINT16                         Pre;
1332   MTRR_MEMORY_CACHE_TYPE         LowestType;
1333   MTRR_MEMORY_CACHE_TYPE         LowestPrecedentType;
1334 
1335   Base   = Vertices[Start].Address;
1336   Length = Vertices[Stop].Address - Base;
1337 
1338   LowestType = MtrrLibLowestType (Types);
1339 
1340   //
1341   // Clear the lowest type (highest bit) to get the precedent types
1342   //
1343   PrecedentTypes = ~(1 << LowestType) & Types;
1344   LowestPrecedentType = MtrrLibLowestType (PrecedentTypes);
1345 
1346   if (Mtrrs == NULL) {
1347     Weight[M(Start, Stop)] = ((LowestType == DefaultType) ? 0 : 1);
1348     Weight[O(Start, Stop)] = ((LowestType == DefaultType) ? 1 : 0);
1349   }
1350 
1351   // Add all high level ranges
1352   HBase = MAX_UINT64;
1353   HLength = 0;
1354   for (Index = 0; Index < RangeCount; Index++) {
1355     if (Length == 0) {
1356       break;
1357     }
1358     if ((Base < Ranges[Index].BaseAddress) || (Ranges[Index].BaseAddress + Ranges[Index].Length <= Base)) {
1359       continue;
1360     }
1361 
1362     //
1363     // Base is in the Range[Index]
1364     //
1365     if (Base + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) {
1366       SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - Base;
1367     } else {
1368       SubLength = Length;
1369     }
1370     if (((1 << Ranges[Index].Type) & PrecedentTypes) != 0) {
1371       //
1372       // Meet a range whose types take precedence.
1373       // Update the [HBase, HBase + HLength) to include the range,
1374       // [HBase, HBase + HLength) may contain sub ranges with 2 different types, and both take precedence.
1375       //
1376       if (HBase == MAX_UINT64) {
1377         HBase = Base;
1378       }
1379       HLength += SubLength;
1380     }
1381 
1382     Base += SubLength;
1383     Length -= SubLength;
1384 
1385     if (HLength == 0) {
1386       continue;
1387     }
1388 
1389     if ((Ranges[Index].Type == LowestType) || (Length == 0)) { // meet low type or end
1390 
1391       //
1392       // Add the MTRRs for each high priority type range
1393       // the range[HBase, HBase + HLength) contains only two types.
1394       // We might use positive or subtractive, depending on which way uses less MTRR
1395       //
1396       for (SubStart = Start; SubStart <= Stop; SubStart++) {
1397         if (Vertices[SubStart].Address == HBase) {
1398           break;
1399         }
1400       }
1401 
1402       for (SubStop = SubStart; SubStop <= Stop; SubStop++) {
1403         if (Vertices[SubStop].Address == HBase + HLength) {
1404           break;
1405         }
1406       }
1407       ASSERT (Vertices[SubStart].Address == HBase);
1408       ASSERT (Vertices[SubStop].Address == HBase + HLength);
1409 
1410       if ((TypeCount == 2) || (SubStart == SubStop - 1)) {
1411         //
1412         // add subtractive MTRRs for [HBase, HBase + HLength)
1413         // [HBase, HBase + HLength) contains only one type.
1414         // while - loop is to split the range to MTRR - compliant aligned range.
1415         //
1416         if (Mtrrs == NULL) {
1417           Weight[M (Start, Stop)] += (UINT8)(SubStop - SubStart);
1418         } else {
1419           while (SubStart != SubStop) {
1420             Status = MtrrLibAppendVariableMtrr (
1421               Mtrrs, MtrrCapacity, MtrrCount,
1422               Vertices[SubStart].Address, Vertices[SubStart].Length, Vertices[SubStart].Type
1423             );
1424             if (RETURN_ERROR (Status)) {
1425               return Status;
1426             }
1427             SubStart++;
1428           }
1429         }
1430       } else {
1431         ASSERT (TypeCount == 3);
1432         MtrrLibCalculateLeastMtrrs (VertexCount, Vertices, Weight, SubStart, SubStop, TRUE);
1433 
1434         if (Mtrrs == NULL) {
1435           Weight[M (Start, Stop)] += Vertices[SubStop].Weight;
1436         } else {
1437           // When we need to collect the optimal path from SubStart to SubStop
1438           while (SubStop != SubStart) {
1439             Cur = SubStop;
1440             Pre = Vertices[Cur].Previous;
1441             SubStop = Pre;
1442 
1443             if (Weight[M (Pre, Cur)] + Weight[O (Pre, Cur)] != 0) {
1444               Status = MtrrLibAppendVariableMtrr (
1445                 Mtrrs, MtrrCapacity, MtrrCount,
1446                 Vertices[Pre].Address, Vertices[Cur].Address - Vertices[Pre].Address,
1447                 (Pre != Cur - 1) ? LowestPrecedentType : Vertices[Pre].Type
1448               );
1449               if (RETURN_ERROR (Status)) {
1450                 return Status;
1451               }
1452             }
1453             if (Pre != Cur - 1) {
1454               Status = MtrrLibCalculateSubtractivePath (
1455                 DefaultType, A0,
1456                 Ranges, RangeCount,
1457                 VertexCount, Vertices, Weight,
1458                 Pre, Cur, PrecedentTypes, 2,
1459                 Mtrrs, MtrrCapacity, MtrrCount
1460               );
1461               if (RETURN_ERROR (Status)) {
1462                 return Status;
1463               }
1464             }
1465           }
1466         }
1467 
1468       }
1469       //
1470       // Reset HBase, HLength
1471       //
1472       HBase = MAX_UINT64;
1473       HLength = 0;
1474     }
1475   }
1476   return RETURN_SUCCESS;
1477 }
1478 
1479 /**
1480   Calculate MTRR settings to cover the specified memory ranges.
1481 
1482   @param DefaultType  Default memory type.
1483   @param A0           Alignment to use when base address is 0.
1484   @param Ranges       Memory range array holding the memory type
1485                       settings for all memory address.
1486   @param RangeCount   Count of memory ranges.
1487   @param Scratch      A temporary scratch buffer that is used to perform the calculation.
1488                       This is an optional parameter that may be NULL.
1489   @param ScratchSize  Pointer to the size in bytes of the scratch buffer.
1490                       It may be updated to the actual required size when the calculation
1491                       needs more scratch buffer.
1492   @param Mtrrs        Array holding all MTRR settings.
1493   @param MtrrCapacity Capacity of the MTRR array.
1494   @param MtrrCount    The count of MTRR settings in array.
1495 
1496   @retval RETURN_SUCCESS          Variable MTRRs are allocated successfully.
1497   @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1498   @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
1499 **/
1500 RETURN_STATUS
MtrrLibCalculateMtrrs(IN MTRR_MEMORY_CACHE_TYPE DefaultType,IN UINT64 A0,IN CONST MTRR_MEMORY_RANGE * Ranges,IN UINTN RangeCount,IN VOID * Scratch,IN OUT UINTN * ScratchSize,IN OUT MTRR_MEMORY_RANGE * Mtrrs,IN UINT32 MtrrCapacity,IN OUT UINT32 * MtrrCount)1501 MtrrLibCalculateMtrrs (
1502   IN MTRR_MEMORY_CACHE_TYPE  DefaultType,
1503   IN UINT64                  A0,
1504   IN CONST MTRR_MEMORY_RANGE *Ranges,
1505   IN UINTN                   RangeCount,
1506   IN VOID                    *Scratch,
1507   IN OUT UINTN               *ScratchSize,
1508   IN OUT MTRR_MEMORY_RANGE   *Mtrrs,
1509   IN UINT32                  MtrrCapacity,
1510   IN OUT UINT32              *MtrrCount
1511   )
1512 {
1513   UINT64                    Base0;
1514   UINT64                    Base1;
1515   UINTN                     Index;
1516   UINT64                    Base;
1517   UINT64                    Length;
1518   UINT64                    Alignment;
1519   UINT64                    SubLength;
1520   MTRR_LIB_ADDRESS          *Vertices;
1521   UINT8                     *Weight;
1522   UINT32                    VertexIndex;
1523   UINT32                    VertexCount;
1524   UINTN                     RequiredScratchSize;
1525   UINT8                     TypeCount;
1526   UINT16                    Start;
1527   UINT16                    Stop;
1528   UINT8                     Type;
1529   RETURN_STATUS             Status;
1530 
1531   Base0 = Ranges[0].BaseAddress;
1532   Base1 = Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length;
1533   MTRR_LIB_ASSERT_ALIGNED (Base0, Base1 - Base0);
1534 
1535   //
1536   // Count the number of vertices.
1537   //
1538   Vertices = (MTRR_LIB_ADDRESS*)Scratch;
1539   for (VertexIndex = 0, Index = 0; Index < RangeCount; Index++) {
1540     Base = Ranges[Index].BaseAddress;
1541     Length = Ranges[Index].Length;
1542     while (Length != 0) {
1543       Alignment = MtrrLibBiggestAlignment (Base, A0);
1544       SubLength = Alignment;
1545       if (SubLength > Length) {
1546         SubLength = GetPowerOfTwo64 (Length);
1547       }
1548       if (VertexIndex < *ScratchSize / sizeof (*Vertices)) {
1549         Vertices[VertexIndex].Address   = Base;
1550         Vertices[VertexIndex].Alignment = Alignment;
1551         Vertices[VertexIndex].Type      = Ranges[Index].Type;
1552         Vertices[VertexIndex].Length    = SubLength;
1553       }
1554       Base   += SubLength;
1555       Length -= SubLength;
1556       VertexIndex++;
1557     }
1558   }
1559   //
1560   // Vertices[VertexIndex] = Base1, so whole vertex count is (VertexIndex + 1).
1561   //
1562   VertexCount = VertexIndex + 1;
1563   DEBUG ((
1564     DEBUG_CACHE, "  Count of vertices (%016llx - %016llx) = %d\n",
1565     Ranges[0].BaseAddress, Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length, VertexCount
1566     ));
1567   ASSERT (VertexCount < MAX_UINT16);
1568 
1569   RequiredScratchSize = VertexCount * sizeof (*Vertices) + VertexCount * VertexCount * sizeof (*Weight);
1570   if (*ScratchSize < RequiredScratchSize) {
1571     *ScratchSize = RequiredScratchSize;
1572     return RETURN_BUFFER_TOO_SMALL;
1573   }
1574   Vertices[VertexCount - 1].Address = Base1;
1575 
1576   Weight = (UINT8 *) &Vertices[VertexCount];
1577   for (VertexIndex = 0; VertexIndex < VertexCount; VertexIndex++) {
1578     //
1579     // Set optional weight between vertices and self->self to 0
1580     //
1581     SetMem (&Weight[M(VertexIndex, 0)], VertexIndex + 1, 0);
1582     //
1583     // Set mandatory weight between vertices to MAX_WEIGHT
1584     //
1585     SetMem (&Weight[M (VertexIndex, VertexIndex + 1)], VertexCount - VertexIndex - 1, MAX_WEIGHT);
1586 
1587     // Final result looks like:
1588     //   00 FF FF FF
1589     //   00 00 FF FF
1590     //   00 00 00 FF
1591     //   00 00 00 00
1592   }
1593 
1594   //
1595   // Set mandatory weight and optional weight for adjacent vertices
1596   //
1597   for (VertexIndex = 0; VertexIndex < VertexCount - 1; VertexIndex++) {
1598     if (Vertices[VertexIndex].Type != DefaultType) {
1599       Weight[M (VertexIndex, VertexIndex + 1)] = 1;
1600       Weight[O (VertexIndex, VertexIndex + 1)] = 0;
1601     } else {
1602       Weight[M (VertexIndex, VertexIndex + 1)] = 0;
1603       Weight[O (VertexIndex, VertexIndex + 1)] = 1;
1604     }
1605   }
1606 
1607   for (TypeCount = 2; TypeCount <= 3; TypeCount++) {
1608     for (Start = 0; Start < VertexCount; Start++) {
1609       for (Stop = Start + 2; Stop < VertexCount; Stop++) {
1610         ASSERT (Vertices[Stop].Address > Vertices[Start].Address);
1611         Length = Vertices[Stop].Address - Vertices[Start].Address;
1612         if (Length > Vertices[Start].Alignment) {
1613           //
1614           // Pickup a new Start when [Start, Stop) cannot be described by one MTRR.
1615           //
1616           break;
1617         }
1618         if ((Weight[M(Start, Stop)] == MAX_WEIGHT) && MtrrLibIsPowerOfTwo (Length)) {
1619           if (MtrrLibGetNumberOfTypes (
1620                 Ranges, RangeCount, Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address, &Type
1621                 ) == TypeCount) {
1622             //
1623             // Update the Weight[Start, Stop] using subtractive path.
1624             //
1625             MtrrLibCalculateSubtractivePath (
1626               DefaultType, A0,
1627               Ranges, RangeCount,
1628               (UINT16)VertexCount, Vertices, Weight,
1629               Start, Stop, Type, TypeCount,
1630               NULL, 0, NULL
1631               );
1632           } else if (TypeCount == 2) {
1633             //
1634             // Pick up a new Start when we expect 2-type range, but 3-type range is met.
1635             // Because no matter how Stop is increased, we always meet 3-type range.
1636             //
1637             break;
1638           }
1639         }
1640       }
1641     }
1642   }
1643 
1644   Status = RETURN_SUCCESS;
1645   MtrrLibCalculateLeastMtrrs ((UINT16) VertexCount, Vertices, Weight, 0, (UINT16) VertexCount - 1, FALSE);
1646   Stop = (UINT16) VertexCount - 1;
1647   while (Stop != 0) {
1648     Start = Vertices[Stop].Previous;
1649     TypeCount = MAX_UINT8;
1650     Type = 0;
1651     if (Weight[M(Start, Stop)] != 0) {
1652       TypeCount = MtrrLibGetNumberOfTypes (Ranges, RangeCount, Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address, &Type);
1653       Status = MtrrLibAppendVariableMtrr (
1654         Mtrrs, MtrrCapacity, MtrrCount,
1655         Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address,
1656         MtrrLibLowestType (Type)
1657         );
1658       if (RETURN_ERROR (Status)) {
1659         break;
1660       }
1661     }
1662 
1663     if (Start != Stop - 1) {
1664       //
1665       // substractive path
1666       //
1667       if (TypeCount == MAX_UINT8) {
1668         TypeCount = MtrrLibGetNumberOfTypes (
1669                       Ranges, RangeCount, Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address, &Type
1670                       );
1671       }
1672       Status = MtrrLibCalculateSubtractivePath (
1673                  DefaultType, A0,
1674                  Ranges, RangeCount,
1675                  (UINT16) VertexCount, Vertices, Weight, Start, Stop,
1676                  Type, TypeCount,
1677                  Mtrrs, MtrrCapacity, MtrrCount
1678                  );
1679       if (RETURN_ERROR (Status)) {
1680         break;
1681       }
1682     }
1683     Stop = Start;
1684   }
1685   return Status;
1686 }
1687 
1688 
1689 /**
1690   Apply the fixed MTRR settings to memory range array.
1691 
1692   @param Fixed             The fixed MTRR settings.
1693   @param Ranges            Return the memory range array holding memory type
1694                            settings for all memory address.
1695   @param RangeCapacity     The capacity of memory range array.
1696   @param RangeCount        Return the count of memory range.
1697 
1698   @retval RETURN_SUCCESS          The memory range array is returned successfully.
1699   @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1700 **/
1701 RETURN_STATUS
MtrrLibApplyFixedMtrrs(IN MTRR_FIXED_SETTINGS * Fixed,IN OUT MTRR_MEMORY_RANGE * Ranges,IN UINTN RangeCapacity,IN OUT UINTN * RangeCount)1702 MtrrLibApplyFixedMtrrs (
1703   IN     MTRR_FIXED_SETTINGS  *Fixed,
1704   IN OUT MTRR_MEMORY_RANGE    *Ranges,
1705   IN     UINTN                RangeCapacity,
1706   IN OUT UINTN                *RangeCount
1707   )
1708 {
1709   RETURN_STATUS               Status;
1710   UINTN                       MsrIndex;
1711   UINTN                       Index;
1712   MTRR_MEMORY_CACHE_TYPE      MemoryType;
1713   UINT64                      Base;
1714 
1715   Base = 0;
1716   for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {
1717     ASSERT (Base == mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress);
1718     for (Index = 0; Index < sizeof (UINT64); Index++) {
1719       MemoryType = (MTRR_MEMORY_CACHE_TYPE)((UINT8 *)(&Fixed->Mtrr[MsrIndex]))[Index];
1720       Status = MtrrLibSetMemoryType (
1721                  Ranges, RangeCapacity, RangeCount, Base, mMtrrLibFixedMtrrTable[MsrIndex].Length, MemoryType
1722                  );
1723       if (Status == RETURN_OUT_OF_RESOURCES) {
1724         return Status;
1725       }
1726       Base += mMtrrLibFixedMtrrTable[MsrIndex].Length;
1727     }
1728   }
1729   ASSERT (Base == BASE_1MB);
1730   return RETURN_SUCCESS;
1731 }
1732 
1733 /**
1734   Apply the variable MTRR settings to memory range array.
1735 
1736   @param VariableMtrr      The variable MTRR array.
1737   @param VariableMtrrCount The count of variable MTRRs.
1738   @param Ranges            Return the memory range array with new MTRR settings applied.
1739   @param RangeCapacity     The capacity of memory range array.
1740   @param RangeCount        Return the count of memory range.
1741 
1742   @retval RETURN_SUCCESS          The memory range array is returned successfully.
1743   @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
1744 **/
1745 RETURN_STATUS
MtrrLibApplyVariableMtrrs(IN CONST MTRR_MEMORY_RANGE * VariableMtrr,IN UINT32 VariableMtrrCount,IN OUT MTRR_MEMORY_RANGE * Ranges,IN UINTN RangeCapacity,IN OUT UINTN * RangeCount)1746 MtrrLibApplyVariableMtrrs (
1747   IN     CONST MTRR_MEMORY_RANGE *VariableMtrr,
1748   IN     UINT32                  VariableMtrrCount,
1749   IN OUT MTRR_MEMORY_RANGE       *Ranges,
1750   IN     UINTN                   RangeCapacity,
1751   IN OUT UINTN                   *RangeCount
1752   )
1753 {
1754   RETURN_STATUS                  Status;
1755   UINTN                          Index;
1756 
1757   //
1758   // WT > WB
1759   // UC > *
1760   // UC > * (except WB, UC) > WB
1761   //
1762 
1763   //
1764   // 1. Set WB
1765   //
1766   for (Index = 0; Index < VariableMtrrCount; Index++) {
1767     if ((VariableMtrr[Index].Length != 0) && (VariableMtrr[Index].Type == CacheWriteBack)) {
1768       Status = MtrrLibSetMemoryType (
1769         Ranges, RangeCapacity, RangeCount,
1770         VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type
1771       );
1772       if (Status == RETURN_OUT_OF_RESOURCES) {
1773         return Status;
1774       }
1775     }
1776   }
1777 
1778   //
1779   // 2. Set other types than WB or UC
1780   //
1781   for (Index = 0; Index < VariableMtrrCount; Index++) {
1782     if ((VariableMtrr[Index].Length != 0) &&
1783         (VariableMtrr[Index].Type != CacheWriteBack) && (VariableMtrr[Index].Type != CacheUncacheable)) {
1784       Status = MtrrLibSetMemoryType (
1785                  Ranges, RangeCapacity, RangeCount,
1786                  VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type
1787                  );
1788       if (Status == RETURN_OUT_OF_RESOURCES) {
1789         return Status;
1790       }
1791     }
1792   }
1793 
1794   //
1795   // 3. Set UC
1796   //
1797   for (Index = 0; Index < VariableMtrrCount; Index++) {
1798     if (VariableMtrr[Index].Length != 0 && VariableMtrr[Index].Type == CacheUncacheable) {
1799       Status = MtrrLibSetMemoryType (
1800                  Ranges, RangeCapacity, RangeCount,
1801                  VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type
1802                  );
1803       if (Status == RETURN_OUT_OF_RESOURCES) {
1804         return Status;
1805       }
1806     }
1807   }
1808   return RETURN_SUCCESS;
1809 }
1810 
1811 /**
1812   Return the memory type bit mask that's compatible to first type in the Ranges.
1813 
1814   @param Ranges     Memory range array holding the memory type
1815                     settings for all memory address.
1816   @param RangeCount Count of memory ranges.
1817 
1818   @return Compatible memory type bit mask.
1819 **/
1820 UINT8
MtrrLibGetCompatibleTypes(IN CONST MTRR_MEMORY_RANGE * Ranges,IN UINTN RangeCount)1821 MtrrLibGetCompatibleTypes (
1822   IN CONST MTRR_MEMORY_RANGE *Ranges,
1823   IN UINTN                   RangeCount
1824   )
1825 {
1826   ASSERT (RangeCount != 0);
1827 
1828   switch (Ranges[0].Type) {
1829   case CacheWriteBack:
1830   case CacheWriteThrough:
1831     return (1 << CacheWriteBack) | (1 << CacheWriteThrough) | (1 << CacheUncacheable);
1832     break;
1833 
1834   case CacheWriteCombining:
1835   case CacheWriteProtected:
1836     return (1 << Ranges[0].Type) | (1 << CacheUncacheable);
1837     break;
1838 
1839   case CacheUncacheable:
1840     if (RangeCount == 1) {
1841       return (1 << CacheUncacheable);
1842     }
1843     return MtrrLibGetCompatibleTypes (&Ranges[1], RangeCount - 1);
1844     break;
1845 
1846   case CacheInvalid:
1847   default:
1848     ASSERT (FALSE);
1849     break;
1850   }
1851   return 0;
1852 }
1853 
1854 /**
1855   Overwrite the destination MTRR settings with the source MTRR settings.
1856   This routine is to make sure the modification to destination MTRR settings
1857   is as small as possible.
1858 
1859   @param DstMtrrs     Destination MTRR settings.
1860   @param DstMtrrCount Count of destination MTRR settings.
1861   @param SrcMtrrs     Source MTRR settings.
1862   @param SrcMtrrCount Count of source MTRR settings.
1863   @param Modified     Flag array to indicate which destination MTRR setting is modified.
1864 **/
1865 VOID
MtrrLibMergeVariableMtrr(MTRR_MEMORY_RANGE * DstMtrrs,UINT32 DstMtrrCount,MTRR_MEMORY_RANGE * SrcMtrrs,UINT32 SrcMtrrCount,BOOLEAN * Modified)1866 MtrrLibMergeVariableMtrr (
1867   MTRR_MEMORY_RANGE *DstMtrrs,
1868   UINT32            DstMtrrCount,
1869   MTRR_MEMORY_RANGE *SrcMtrrs,
1870   UINT32            SrcMtrrCount,
1871   BOOLEAN           *Modified
1872   )
1873 {
1874   UINT32          DstIndex;
1875   UINT32          SrcIndex;
1876 
1877   ASSERT (SrcMtrrCount <= DstMtrrCount);
1878 
1879   for (DstIndex = 0; DstIndex < DstMtrrCount; DstIndex++) {
1880     Modified[DstIndex] = FALSE;
1881 
1882     if (DstMtrrs[DstIndex].Length == 0) {
1883       continue;
1884     }
1885     for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) {
1886       if (DstMtrrs[DstIndex].BaseAddress == SrcMtrrs[SrcIndex].BaseAddress &&
1887         DstMtrrs[DstIndex].Length == SrcMtrrs[SrcIndex].Length &&
1888         DstMtrrs[DstIndex].Type == SrcMtrrs[SrcIndex].Type) {
1889         break;
1890       }
1891     }
1892 
1893     if (SrcIndex == SrcMtrrCount) {
1894       //
1895       // Remove the one from DstMtrrs which is not in SrcMtrrs
1896       //
1897       DstMtrrs[DstIndex].Length = 0;
1898       Modified[DstIndex] = TRUE;
1899     } else {
1900       //
1901       // Remove the one from SrcMtrrs which is also in DstMtrrs
1902       //
1903       SrcMtrrs[SrcIndex].Length = 0;
1904     }
1905   }
1906 
1907   //
1908   // Now valid MTRR only exists in either DstMtrrs or SrcMtrrs.
1909   // Merge MTRRs from SrcMtrrs to DstMtrrs
1910   //
1911   DstIndex = 0;
1912   for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) {
1913     if (SrcMtrrs[SrcIndex].Length != 0) {
1914 
1915       //
1916       // Find the empty slot in DstMtrrs
1917       //
1918       while (DstIndex < DstMtrrCount) {
1919         if (DstMtrrs[DstIndex].Length == 0) {
1920           break;
1921         }
1922         DstIndex++;
1923       }
1924       ASSERT (DstIndex < DstMtrrCount);
1925       CopyMem (&DstMtrrs[DstIndex], &SrcMtrrs[SrcIndex], sizeof (SrcMtrrs[0]));
1926       Modified[DstIndex] = TRUE;
1927     }
1928   }
1929 }
1930 
1931 /**
1932   Calculate the variable MTRR settings for all memory ranges.
1933 
1934   @param DefaultType          Default memory type.
1935   @param A0                   Alignment to use when base address is 0.
1936   @param Ranges               Memory range array holding the memory type
1937                               settings for all memory address.
1938   @param RangeCount           Count of memory ranges.
1939   @param Scratch              Scratch buffer to be used in MTRR calculation.
1940   @param ScratchSize          Pointer to the size of scratch buffer.
1941   @param VariableMtrr         Array holding all MTRR settings.
1942   @param VariableMtrrCapacity Capacity of the MTRR array.
1943   @param VariableMtrrCount    The count of MTRR settings in array.
1944 
1945   @retval RETURN_SUCCESS          Variable MTRRs are allocated successfully.
1946   @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
1947   @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
1948                                   The required scratch buffer size is returned through ScratchSize.
1949 **/
1950 RETURN_STATUS
MtrrLibSetMemoryRanges(IN MTRR_MEMORY_CACHE_TYPE DefaultType,IN UINT64 A0,IN MTRR_MEMORY_RANGE * Ranges,IN UINTN RangeCount,IN VOID * Scratch,IN OUT UINTN * ScratchSize,OUT MTRR_MEMORY_RANGE * VariableMtrr,IN UINT32 VariableMtrrCapacity,OUT UINT32 * VariableMtrrCount)1951 MtrrLibSetMemoryRanges (
1952   IN MTRR_MEMORY_CACHE_TYPE DefaultType,
1953   IN UINT64                 A0,
1954   IN MTRR_MEMORY_RANGE      *Ranges,
1955   IN UINTN                  RangeCount,
1956   IN VOID                   *Scratch,
1957   IN OUT UINTN              *ScratchSize,
1958   OUT MTRR_MEMORY_RANGE     *VariableMtrr,
1959   IN UINT32                 VariableMtrrCapacity,
1960   OUT UINT32                *VariableMtrrCount
1961   )
1962 {
1963   RETURN_STATUS             Status;
1964   UINT32                    Index;
1965   UINT64                    Base0;
1966   UINT64                    Base1;
1967   UINT64                    Alignment;
1968   UINT8                     CompatibleTypes;
1969   UINT64                    Length;
1970   UINT32                    End;
1971   UINTN                     ActualScratchSize;
1972   UINTN                     BiggestScratchSize;
1973 
1974   *VariableMtrrCount = 0;
1975 
1976   //
1977   // Since the whole ranges need multiple calls of MtrrLibCalculateMtrrs().
1978   // Each call needs different scratch buffer size.
1979   // When the provided scratch buffer size is not sufficient in any call,
1980   // set the GetActualScratchSize to TRUE, and following calls will only
1981   // calculate the actual scratch size for the caller.
1982   //
1983   BiggestScratchSize = 0;
1984 
1985   for (Index = 0; Index < RangeCount;) {
1986     Base0 = Ranges[Index].BaseAddress;
1987 
1988     //
1989     // Full step is optimal
1990     //
1991     while (Index < RangeCount) {
1992       ASSERT (Ranges[Index].BaseAddress == Base0);
1993       Alignment = MtrrLibBiggestAlignment (Base0, A0);
1994       while (Base0 + Alignment <= Ranges[Index].BaseAddress + Ranges[Index].Length) {
1995         if ((BiggestScratchSize <= *ScratchSize) && (Ranges[Index].Type != DefaultType)) {
1996           Status = MtrrLibAppendVariableMtrr (
1997             VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
1998             Base0, Alignment, Ranges[Index].Type
1999             );
2000           if (RETURN_ERROR (Status)) {
2001             return Status;
2002           }
2003         }
2004         Base0 += Alignment;
2005         Alignment = MtrrLibBiggestAlignment (Base0, A0);
2006       }
2007 
2008       //
2009       // Remove the above range from Ranges[Index]
2010       //
2011       Ranges[Index].Length -= Base0 - Ranges[Index].BaseAddress;
2012       Ranges[Index].BaseAddress = Base0;
2013       if (Ranges[Index].Length != 0) {
2014         break;
2015       } else {
2016         Index++;
2017       }
2018     }
2019 
2020     if (Index == RangeCount) {
2021       break;
2022     }
2023 
2024     //
2025     // Find continous ranges [Base0, Base1) which could be combined by MTRR.
2026     // Per SDM, the compatible types between[B0, B1) are:
2027     //   UC, *
2028     //   WB, WT
2029     //   UC, WB, WT
2030     //
2031     CompatibleTypes = MtrrLibGetCompatibleTypes (&Ranges[Index], RangeCount - Index);
2032 
2033     End = Index; // End points to last one that matches the CompatibleTypes.
2034     while (End + 1 < RangeCount) {
2035       if (((1 << Ranges[End + 1].Type) & CompatibleTypes) == 0) {
2036         break;
2037       }
2038       End++;
2039     }
2040     Alignment = MtrrLibBiggestAlignment (Base0, A0);
2041     Length    = GetPowerOfTwo64 (Ranges[End].BaseAddress + Ranges[End].Length - Base0);
2042     Base1     = Base0 + MIN (Alignment, Length);
2043 
2044     //
2045     // Base1 may not in Ranges[End]. Update End to the range Base1 belongs to.
2046     //
2047     End = Index;
2048     while (End + 1 < RangeCount) {
2049       if (Base1 <= Ranges[End + 1].BaseAddress) {
2050         break;
2051       }
2052       End++;
2053     }
2054 
2055     Length = Ranges[End].Length;
2056     Ranges[End].Length = Base1 - Ranges[End].BaseAddress;
2057     ActualScratchSize  = *ScratchSize;
2058     Status = MtrrLibCalculateMtrrs (
2059                DefaultType, A0,
2060                &Ranges[Index], End + 1 - Index,
2061                Scratch, &ActualScratchSize,
2062                VariableMtrr, VariableMtrrCapacity, VariableMtrrCount
2063                );
2064     if (Status == RETURN_BUFFER_TOO_SMALL) {
2065       BiggestScratchSize = MAX (BiggestScratchSize, ActualScratchSize);
2066       //
2067       // Ignore this error, because we need to calculate the biggest
2068       // scratch buffer size.
2069       //
2070       Status = RETURN_SUCCESS;
2071     }
2072     if (RETURN_ERROR (Status)) {
2073       return Status;
2074     }
2075 
2076     if (Length != Ranges[End].Length) {
2077       Ranges[End].BaseAddress = Base1;
2078       Ranges[End].Length = Length - Ranges[End].Length;
2079       Index = End;
2080     } else {
2081       Index = End + 1;
2082     }
2083   }
2084 
2085   if (*ScratchSize < BiggestScratchSize) {
2086     *ScratchSize = BiggestScratchSize;
2087     return RETURN_BUFFER_TOO_SMALL;
2088   }
2089   return RETURN_SUCCESS;
2090 }
2091 
2092 /**
2093   Set the below-1MB memory attribute to fixed MTRR buffer.
2094   Modified flag array indicates which fixed MTRR is modified.
2095 
2096   @param [in, out] ClearMasks    The bits (when set) to clear in the fixed MTRR MSR.
2097   @param [in, out] OrMasks       The bits to set in the fixed MTRR MSR.
2098   @param [in]      BaseAddress   Base address.
2099   @param [in]      Length        Length.
2100   @param [in]      Type          Memory type.
2101 
2102   @retval RETURN_SUCCESS      The memory attribute is set successfully.
2103   @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid
2104                               for the fixed MTRRs.
2105 **/
2106 RETURN_STATUS
MtrrLibSetBelow1MBMemoryAttribute(IN OUT UINT64 * ClearMasks,IN OUT UINT64 * OrMasks,IN PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN MTRR_MEMORY_CACHE_TYPE Type)2107 MtrrLibSetBelow1MBMemoryAttribute (
2108   IN OUT UINT64                  *ClearMasks,
2109   IN OUT UINT64                  *OrMasks,
2110   IN PHYSICAL_ADDRESS            BaseAddress,
2111   IN UINT64                      Length,
2112   IN MTRR_MEMORY_CACHE_TYPE      Type
2113   )
2114 {
2115   RETURN_STATUS             Status;
2116   UINT32                    MsrIndex;
2117   UINT64                    ClearMask;
2118   UINT64                    OrMask;
2119 
2120   ASSERT (BaseAddress < BASE_1MB);
2121 
2122   MsrIndex = (UINT32)-1;
2123   while ((BaseAddress < BASE_1MB) && (Length != 0)) {
2124     Status = MtrrLibProgramFixedMtrr (Type, &BaseAddress, &Length, &MsrIndex, &ClearMask, &OrMask);
2125     if (RETURN_ERROR (Status)) {
2126       return Status;
2127     }
2128     ClearMasks[MsrIndex] = ClearMasks[MsrIndex] | ClearMask;
2129     OrMasks[MsrIndex]    = (OrMasks[MsrIndex] & ~ClearMask) | OrMask;
2130   }
2131   return RETURN_SUCCESS;
2132 }
2133 
2134 /**
2135   This function attempts to set the attributes into MTRR setting buffer for multiple memory ranges.
2136 
2137   @param[in, out]  MtrrSetting  MTRR setting buffer to be set.
2138   @param[in]       Scratch      A temporary scratch buffer that is used to perform the calculation.
2139   @param[in, out]  ScratchSize  Pointer to the size in bytes of the scratch buffer.
2140                                 It may be updated to the actual required size when the calculation
2141                                 needs more scratch buffer.
2142   @param[in]       Ranges       Pointer to an array of MTRR_MEMORY_RANGE.
2143                                 When range overlap happens, the last one takes higher priority.
2144                                 When the function returns, either all the attributes are set successfully,
2145                                 or none of them is set.
2146   @param[in]       RangeCount   Count of MTRR_MEMORY_RANGE.
2147 
2148   @retval RETURN_SUCCESS            The attributes were set for all the memory ranges.
2149   @retval RETURN_INVALID_PARAMETER  Length in any range is zero.
2150   @retval RETURN_UNSUPPORTED        The processor does not support one or more bytes of the
2151                                     memory resource range specified by BaseAddress and Length in any range.
2152   @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support for the memory resource
2153                                     range specified by BaseAddress and Length in any range.
2154   @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to modify the attributes of
2155                                     the memory resource ranges.
2156   @retval RETURN_ACCESS_DENIED      The attributes for the memory resource range specified by
2157                                     BaseAddress and Length cannot be modified.
2158   @retval RETURN_BUFFER_TOO_SMALL   The scratch buffer is too small for MTRR calculation.
2159 **/
2160 RETURN_STATUS
2161 EFIAPI
MtrrSetMemoryAttributesInMtrrSettings(IN OUT MTRR_SETTINGS * MtrrSetting,IN VOID * Scratch,IN OUT UINTN * ScratchSize,IN CONST MTRR_MEMORY_RANGE * Ranges,IN UINTN RangeCount)2162 MtrrSetMemoryAttributesInMtrrSettings (
2163   IN OUT MTRR_SETTINGS           *MtrrSetting,
2164   IN     VOID                    *Scratch,
2165   IN OUT UINTN                   *ScratchSize,
2166   IN     CONST MTRR_MEMORY_RANGE *Ranges,
2167   IN     UINTN                   RangeCount
2168   )
2169 {
2170   RETURN_STATUS             Status;
2171   UINT32                    Index;
2172   UINT64                    BaseAddress;
2173   UINT64                    Length;
2174   BOOLEAN                   Above1MbExist;
2175 
2176   UINT64                    MtrrValidBitsMask;
2177   UINT64                    MtrrValidAddressMask;
2178   MTRR_MEMORY_CACHE_TYPE    DefaultType;
2179   MTRR_VARIABLE_SETTINGS    VariableSettings;
2180   MTRR_MEMORY_RANGE         WorkingRanges[2 * ARRAY_SIZE (MtrrSetting->Variables.Mtrr) + 2];
2181   UINTN                     WorkingRangeCount;
2182   BOOLEAN                   Modified;
2183   MTRR_VARIABLE_SETTING     VariableSetting;
2184   UINT32                    OriginalVariableMtrrCount;
2185   UINT32                    FirmwareVariableMtrrCount;
2186   UINT32                    WorkingVariableMtrrCount;
2187   MTRR_MEMORY_RANGE         OriginalVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
2188   MTRR_MEMORY_RANGE         WorkingVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
2189   BOOLEAN                   VariableSettingModified[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
2190 
2191   UINT64                    ClearMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];
2192   UINT64                    OrMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];
2193 
2194   MTRR_CONTEXT              MtrrContext;
2195   BOOLEAN                   MtrrContextValid;
2196 
2197   Status = RETURN_SUCCESS;
2198   MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
2199 
2200   //
2201   // TRUE indicating the accordingly Variable setting needs modificaiton in OriginalVariableMtrr.
2202   //
2203   SetMem (VariableSettingModified, ARRAY_SIZE (VariableSettingModified), FALSE);
2204 
2205   //
2206   // TRUE indicating the caller requests to set variable MTRRs.
2207   //
2208   Above1MbExist             = FALSE;
2209   OriginalVariableMtrrCount = 0;
2210 
2211   //
2212   // 0. Dump the requests.
2213   //
2214   DEBUG_CODE (
2215     DEBUG ((DEBUG_CACHE, "Mtrr: Set Mem Attribute to %a, ScratchSize = %x%a",
2216             (MtrrSetting == NULL) ? "Hardware" : "Buffer", *ScratchSize,
2217             (RangeCount <= 1) ? "," : "\n"
2218             ));
2219     for (Index = 0; Index < RangeCount; Index++) {
2220       DEBUG ((DEBUG_CACHE, " %a: [%016lx, %016lx)\n",
2221               mMtrrMemoryCacheTypeShortName[MIN (Ranges[Index].Type, CacheInvalid)],
2222               Ranges[Index].BaseAddress, Ranges[Index].BaseAddress + Ranges[Index].Length
2223               ));
2224     }
2225   );
2226 
2227   //
2228   // 1. Validate the parameters.
2229   //
2230   if (!IsMtrrSupported ()) {
2231     Status = RETURN_UNSUPPORTED;
2232     goto Exit;
2233   }
2234 
2235   for (Index = 0; Index < RangeCount; Index++) {
2236     if (Ranges[Index].Length == 0) {
2237       Status = RETURN_INVALID_PARAMETER;
2238       goto Exit;
2239     }
2240     if (((Ranges[Index].BaseAddress & ~MtrrValidAddressMask) != 0) ||
2241         ((((Ranges[Index].BaseAddress + Ranges[Index].Length) & ~MtrrValidAddressMask) != 0) &&
2242           (Ranges[Index].BaseAddress + Ranges[Index].Length) != MtrrValidBitsMask + 1)
2243         ) {
2244       //
2245       // Either the BaseAddress or the Limit doesn't follow the alignment requirement.
2246       // Note: It's still valid if Limit doesn't follow the alignment requirement but equals to MAX Address.
2247       //
2248       Status = RETURN_UNSUPPORTED;
2249       goto Exit;
2250     }
2251     if ((Ranges[Index].Type != CacheUncacheable) &&
2252         (Ranges[Index].Type != CacheWriteCombining) &&
2253         (Ranges[Index].Type != CacheWriteThrough) &&
2254         (Ranges[Index].Type != CacheWriteProtected) &&
2255         (Ranges[Index].Type != CacheWriteBack)) {
2256       Status = RETURN_INVALID_PARAMETER;
2257       goto Exit;
2258     }
2259     if (Ranges[Index].BaseAddress + Ranges[Index].Length > BASE_1MB) {
2260       Above1MbExist = TRUE;
2261     }
2262   }
2263 
2264   //
2265   // 2. Apply the above-1MB memory attribute settings.
2266   //
2267   if (Above1MbExist) {
2268     //
2269     // 2.1. Read all variable MTRRs and convert to Ranges.
2270     //
2271     OriginalVariableMtrrCount = GetVariableMtrrCountWorker ();
2272     MtrrGetVariableMtrrWorker (MtrrSetting, OriginalVariableMtrrCount, &VariableSettings);
2273     MtrrLibGetRawVariableRanges (
2274       &VariableSettings, OriginalVariableMtrrCount,
2275       MtrrValidBitsMask, MtrrValidAddressMask, OriginalVariableMtrr
2276       );
2277 
2278     DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);
2279     WorkingRangeCount = 1;
2280     WorkingRanges[0].BaseAddress = 0;
2281     WorkingRanges[0].Length      = MtrrValidBitsMask + 1;
2282     WorkingRanges[0].Type        = DefaultType;
2283 
2284     Status = MtrrLibApplyVariableMtrrs (
2285                OriginalVariableMtrr, OriginalVariableMtrrCount,
2286                WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount);
2287     ASSERT_RETURN_ERROR (Status);
2288 
2289     ASSERT (OriginalVariableMtrrCount >= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs));
2290     FirmwareVariableMtrrCount = OriginalVariableMtrrCount - PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
2291     ASSERT (WorkingRangeCount <= 2 * FirmwareVariableMtrrCount + 1);
2292 
2293     //
2294     // 2.2. Force [0, 1M) to UC, so that it doesn't impact subtraction algorithm.
2295     //
2296     Status = MtrrLibSetMemoryType (
2297                WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount,
2298                0, SIZE_1MB, CacheUncacheable
2299                );
2300     ASSERT (Status != RETURN_OUT_OF_RESOURCES);
2301 
2302     //
2303     // 2.3. Apply the new memory attribute settings to Ranges.
2304     //
2305     Modified = FALSE;
2306     for (Index = 0; Index < RangeCount; Index++) {
2307       BaseAddress = Ranges[Index].BaseAddress;
2308       Length = Ranges[Index].Length;
2309       if (BaseAddress < BASE_1MB) {
2310         if (Length <= BASE_1MB - BaseAddress) {
2311           continue;
2312         }
2313         Length -= BASE_1MB - BaseAddress;
2314         BaseAddress = BASE_1MB;
2315       }
2316       Status = MtrrLibSetMemoryType (
2317                  WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount,
2318                  BaseAddress, Length, Ranges[Index].Type
2319                  );
2320       if (Status == RETURN_ALREADY_STARTED) {
2321         Status = RETURN_SUCCESS;
2322       } else if (Status == RETURN_OUT_OF_RESOURCES) {
2323         goto Exit;
2324       } else {
2325         ASSERT_RETURN_ERROR (Status);
2326         Modified = TRUE;
2327       }
2328     }
2329 
2330     if (Modified) {
2331       //
2332       // 2.4. Calculate the Variable MTRR settings based on the Ranges.
2333       //      Buffer Too Small may be returned if the scratch buffer size is insufficient.
2334       //
2335       Status = MtrrLibSetMemoryRanges (
2336                  DefaultType, LShiftU64 (1, (UINTN)HighBitSet64 (MtrrValidBitsMask)), WorkingRanges, WorkingRangeCount,
2337                  Scratch, ScratchSize,
2338                  WorkingVariableMtrr, FirmwareVariableMtrrCount + 1, &WorkingVariableMtrrCount
2339                  );
2340       if (RETURN_ERROR (Status)) {
2341         goto Exit;
2342       }
2343 
2344       //
2345       // 2.5. Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
2346       //
2347       for (Index = 0; Index < WorkingVariableMtrrCount; Index++) {
2348         if (WorkingVariableMtrr[Index].BaseAddress == 0 && WorkingVariableMtrr[Index].Length == SIZE_1MB) {
2349           ASSERT (WorkingVariableMtrr[Index].Type == CacheUncacheable);
2350           WorkingVariableMtrrCount--;
2351           CopyMem (
2352             &WorkingVariableMtrr[Index], &WorkingVariableMtrr[Index + 1],
2353             (WorkingVariableMtrrCount - Index) * sizeof (WorkingVariableMtrr[0])
2354             );
2355           break;
2356         }
2357       }
2358 
2359       if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {
2360         Status = RETURN_OUT_OF_RESOURCES;
2361         goto Exit;
2362       }
2363 
2364       //
2365       // 2.6. Merge the WorkingVariableMtrr to OriginalVariableMtrr
2366       //      Make sure least modification is made to OriginalVariableMtrr.
2367       //
2368       MtrrLibMergeVariableMtrr (
2369         OriginalVariableMtrr, OriginalVariableMtrrCount,
2370         WorkingVariableMtrr, WorkingVariableMtrrCount,
2371         VariableSettingModified
2372       );
2373     }
2374   }
2375 
2376   //
2377   // 3. Apply the below-1MB memory attribute settings.
2378   //
2379   // (Value & ~0 | 0) still equals to (Value)
2380   //
2381   ZeroMem (ClearMasks, sizeof (ClearMasks));
2382   ZeroMem (OrMasks, sizeof (OrMasks));
2383   for (Index = 0; Index < RangeCount; Index++) {
2384     if (Ranges[Index].BaseAddress >= BASE_1MB) {
2385       continue;
2386     }
2387 
2388     Status = MtrrLibSetBelow1MBMemoryAttribute (
2389                ClearMasks, OrMasks,
2390                Ranges[Index].BaseAddress, Ranges[Index].Length, Ranges[Index].Type
2391                );
2392     if (RETURN_ERROR (Status)) {
2393       goto Exit;
2394     }
2395   }
2396 
2397   MtrrContextValid = FALSE;
2398   //
2399   // 4. Write fixed MTRRs that have been modified
2400   //
2401   for (Index = 0; Index < ARRAY_SIZE (ClearMasks); Index++) {
2402     if (ClearMasks[Index] != 0) {
2403       if (MtrrSetting != NULL) {
2404         MtrrSetting->Fixed.Mtrr[Index] = (MtrrSetting->Fixed.Mtrr[Index] & ~ClearMasks[Index]) | OrMasks[Index];
2405       } else {
2406         if (!MtrrContextValid) {
2407           MtrrLibPreMtrrChange (&MtrrContext);
2408           MtrrContextValid = TRUE;
2409         }
2410         AsmMsrAndThenOr64 (mMtrrLibFixedMtrrTable[Index].Msr, ~ClearMasks[Index], OrMasks[Index]);
2411       }
2412     }
2413   }
2414 
2415   //
2416   // 5. Write variable MTRRs that have been modified
2417   //
2418   for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {
2419     if (VariableSettingModified[Index]) {
2420       if (OriginalVariableMtrr[Index].Length != 0) {
2421         VariableSetting.Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask)
2422                              | (UINT8)OriginalVariableMtrr[Index].Type;
2423         VariableSetting.Mask = ((~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask) | BIT11;
2424       } else {
2425         VariableSetting.Base = 0;
2426         VariableSetting.Mask = 0;
2427       }
2428       if (MtrrSetting != NULL) {
2429         CopyMem (&MtrrSetting->Variables.Mtrr[Index], &VariableSetting, sizeof (VariableSetting));
2430       } else {
2431         if (!MtrrContextValid) {
2432           MtrrLibPreMtrrChange (&MtrrContext);
2433           MtrrContextValid = TRUE;
2434         }
2435         AsmWriteMsr64 (
2436           MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),
2437           VariableSetting.Base
2438         );
2439         AsmWriteMsr64 (
2440           MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),
2441           VariableSetting.Mask
2442         );
2443       }
2444     }
2445   }
2446 
2447   if (MtrrSetting != NULL) {
2448     ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.E = 1;
2449     ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.FE = 1;
2450   } else {
2451     if (MtrrContextValid) {
2452       MtrrLibPostMtrrChange (&MtrrContext);
2453     }
2454   }
2455 
2456 Exit:
2457   DEBUG ((DEBUG_CACHE, "  Result = %r\n", Status));
2458   if (!RETURN_ERROR (Status)) {
2459     MtrrDebugPrintAllMtrrsWorker (MtrrSetting);
2460   }
2461   return Status;
2462 }
2463 
2464 /**
2465   This function attempts to set the attributes into MTRR setting buffer for a memory range.
2466 
2467   @param[in, out]  MtrrSetting  MTRR setting buffer to be set.
2468   @param[in]       BaseAddress  The physical address that is the start address
2469                                 of a memory range.
2470   @param[in]       Length       The size in bytes of the memory range.
2471   @param[in]       Attribute    The bit mask of attributes to set for the
2472                                 memory range.
2473 
2474   @retval RETURN_SUCCESS            The attributes were set for the memory range.
2475   @retval RETURN_INVALID_PARAMETER  Length is zero.
2476   @retval RETURN_UNSUPPORTED        The processor does not support one or more bytes of the
2477                                     memory resource range specified by BaseAddress and Length.
2478   @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support for the memory resource
2479                                     range specified by BaseAddress and Length.
2480   @retval RETURN_ACCESS_DENIED      The attributes for the memory resource range specified by
2481                                     BaseAddress and Length cannot be modified.
2482   @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to modify the attributes of
2483                                     the memory resource range.
2484                                     Multiple memory range attributes setting by calling this API multiple
2485                                     times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean
2486                                     the number of CPU MTRRs are too small to set such memory attributes.
2487                                     Pass the multiple memory range attributes to one call of
2488                                     MtrrSetMemoryAttributesInMtrrSettings() may succeed.
2489   @retval RETURN_BUFFER_TOO_SMALL   The fixed internal scratch buffer is too small for MTRR calculation.
2490                                     Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify
2491                                     external scratch buffer.
2492 **/
2493 RETURN_STATUS
2494 EFIAPI
MtrrSetMemoryAttributeInMtrrSettings(IN OUT MTRR_SETTINGS * MtrrSetting,IN PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN MTRR_MEMORY_CACHE_TYPE Attribute)2495 MtrrSetMemoryAttributeInMtrrSettings (
2496   IN OUT MTRR_SETTINGS       *MtrrSetting,
2497   IN PHYSICAL_ADDRESS        BaseAddress,
2498   IN UINT64                  Length,
2499   IN MTRR_MEMORY_CACHE_TYPE  Attribute
2500   )
2501 {
2502   UINT8                      Scratch[SCRATCH_BUFFER_SIZE];
2503   UINTN                      ScratchSize;
2504   MTRR_MEMORY_RANGE          Range;
2505 
2506   Range.BaseAddress = BaseAddress;
2507   Range.Length      = Length;
2508   Range.Type        = Attribute;
2509   ScratchSize = sizeof (Scratch);
2510   return MtrrSetMemoryAttributesInMtrrSettings (MtrrSetting, Scratch, &ScratchSize, &Range, 1);
2511 }
2512 
2513 /**
2514   This function attempts to set the attributes for a memory range.
2515 
2516   @param[in]  BaseAddress        The physical address that is the start
2517                                  address of a memory range.
2518   @param[in]  Length             The size in bytes of the memory range.
2519   @param[in]  Attributes         The bit mask of attributes to set for the
2520                                  memory range.
2521 
2522   @retval RETURN_SUCCESS            The attributes were set for the memory
2523                                     range.
2524   @retval RETURN_INVALID_PARAMETER  Length is zero.
2525   @retval RETURN_UNSUPPORTED        The processor does not support one or
2526                                     more bytes of the memory resource range
2527                                     specified by BaseAddress and Length.
2528   @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support
2529                                     for the memory resource range specified
2530                                     by BaseAddress and Length.
2531   @retval RETURN_ACCESS_DENIED      The attributes for the memory resource
2532                                     range specified by BaseAddress and Length
2533                                     cannot be modified.
2534   @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to
2535                                     modify the attributes of the memory
2536                                     resource range.
2537                                     Multiple memory range attributes setting by calling this API multiple
2538                                     times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean
2539                                     the number of CPU MTRRs are too small to set such memory attributes.
2540                                     Pass the multiple memory range attributes to one call of
2541                                     MtrrSetMemoryAttributesInMtrrSettings() may succeed.
2542   @retval RETURN_BUFFER_TOO_SMALL   The fixed internal scratch buffer is too small for MTRR calculation.
2543                                     Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify
2544                                     external scratch buffer.
2545 **/
2546 RETURN_STATUS
2547 EFIAPI
MtrrSetMemoryAttribute(IN PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN MTRR_MEMORY_CACHE_TYPE Attribute)2548 MtrrSetMemoryAttribute (
2549   IN PHYSICAL_ADDRESS        BaseAddress,
2550   IN UINT64                  Length,
2551   IN MTRR_MEMORY_CACHE_TYPE  Attribute
2552   )
2553 {
2554   return MtrrSetMemoryAttributeInMtrrSettings (NULL, BaseAddress, Length, Attribute);
2555 }
2556 
2557 /**
2558   Worker function setting variable MTRRs
2559 
2560   @param[in]  VariableSettings   A buffer to hold variable MTRRs content.
2561 
2562 **/
2563 VOID
MtrrSetVariableMtrrWorker(IN MTRR_VARIABLE_SETTINGS * VariableSettings)2564 MtrrSetVariableMtrrWorker (
2565   IN MTRR_VARIABLE_SETTINGS         *VariableSettings
2566   )
2567 {
2568   UINT32  Index;
2569   UINT32  VariableMtrrCount;
2570 
2571   VariableMtrrCount = GetVariableMtrrCountWorker ();
2572   ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->Mtrr));
2573 
2574   for (Index = 0; Index < VariableMtrrCount; Index++) {
2575     AsmWriteMsr64 (
2576       MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),
2577       VariableSettings->Mtrr[Index].Base
2578       );
2579     AsmWriteMsr64 (
2580       MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),
2581       VariableSettings->Mtrr[Index].Mask
2582       );
2583   }
2584 }
2585 
2586 
2587 /**
2588   This function sets variable MTRRs
2589 
2590   @param[in]  VariableSettings   A buffer to hold variable MTRRs content.
2591 
2592   @return The pointer of VariableSettings
2593 
2594 **/
2595 MTRR_VARIABLE_SETTINGS*
2596 EFIAPI
MtrrSetVariableMtrr(IN MTRR_VARIABLE_SETTINGS * VariableSettings)2597 MtrrSetVariableMtrr (
2598   IN MTRR_VARIABLE_SETTINGS         *VariableSettings
2599   )
2600 {
2601   MTRR_CONTEXT  MtrrContext;
2602 
2603   if (!IsMtrrSupported ()) {
2604     return VariableSettings;
2605   }
2606 
2607   MtrrLibPreMtrrChange (&MtrrContext);
2608   MtrrSetVariableMtrrWorker (VariableSettings);
2609   MtrrLibPostMtrrChange (&MtrrContext);
2610   MtrrDebugPrintAllMtrrs ();
2611 
2612   return  VariableSettings;
2613 }
2614 
2615 /**
2616   Worker function setting fixed MTRRs
2617 
2618   @param[in]  FixedSettings  A buffer to hold fixed MTRRs content.
2619 
2620 **/
2621 VOID
MtrrSetFixedMtrrWorker(IN MTRR_FIXED_SETTINGS * FixedSettings)2622 MtrrSetFixedMtrrWorker (
2623   IN MTRR_FIXED_SETTINGS          *FixedSettings
2624   )
2625 {
2626   UINT32  Index;
2627 
2628   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
2629      AsmWriteMsr64 (
2630        mMtrrLibFixedMtrrTable[Index].Msr,
2631        FixedSettings->Mtrr[Index]
2632        );
2633   }
2634 }
2635 
2636 
2637 /**
2638   This function sets fixed MTRRs
2639 
2640   @param[in]  FixedSettings  A buffer to hold fixed MTRRs content.
2641 
2642   @retval The pointer of FixedSettings
2643 
2644 **/
2645 MTRR_FIXED_SETTINGS*
2646 EFIAPI
MtrrSetFixedMtrr(IN MTRR_FIXED_SETTINGS * FixedSettings)2647 MtrrSetFixedMtrr (
2648   IN MTRR_FIXED_SETTINGS          *FixedSettings
2649   )
2650 {
2651   MTRR_CONTEXT  MtrrContext;
2652 
2653   if (!IsMtrrSupported ()) {
2654     return FixedSettings;
2655   }
2656 
2657   MtrrLibPreMtrrChange (&MtrrContext);
2658   MtrrSetFixedMtrrWorker (FixedSettings);
2659   MtrrLibPostMtrrChange (&MtrrContext);
2660   MtrrDebugPrintAllMtrrs ();
2661 
2662   return FixedSettings;
2663 }
2664 
2665 
2666 /**
2667   This function gets the content in all MTRRs (variable and fixed)
2668 
2669   @param[out]  MtrrSetting  A buffer to hold all MTRRs content.
2670 
2671   @retval the pointer of MtrrSetting
2672 
2673 **/
2674 MTRR_SETTINGS *
2675 EFIAPI
MtrrGetAllMtrrs(OUT MTRR_SETTINGS * MtrrSetting)2676 MtrrGetAllMtrrs (
2677   OUT MTRR_SETTINGS                *MtrrSetting
2678   )
2679 {
2680   if (!IsMtrrSupported ()) {
2681     return MtrrSetting;
2682   }
2683 
2684   //
2685   // Get fixed MTRRs
2686   //
2687   MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);
2688 
2689   //
2690   // Get variable MTRRs
2691   //
2692   MtrrGetVariableMtrrWorker (
2693     NULL,
2694     GetVariableMtrrCountWorker (),
2695     &MtrrSetting->Variables
2696     );
2697 
2698   //
2699   // Get MTRR_DEF_TYPE value
2700   //
2701   MtrrSetting->MtrrDefType = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
2702 
2703   return MtrrSetting;
2704 }
2705 
2706 
2707 /**
2708   This function sets all MTRRs (variable and fixed)
2709 
2710   @param[in]  MtrrSetting  A buffer holding all MTRRs content.
2711 
2712   @retval The pointer of MtrrSetting
2713 
2714 **/
2715 MTRR_SETTINGS *
2716 EFIAPI
MtrrSetAllMtrrs(IN MTRR_SETTINGS * MtrrSetting)2717 MtrrSetAllMtrrs (
2718   IN MTRR_SETTINGS                *MtrrSetting
2719   )
2720 {
2721   MTRR_CONTEXT  MtrrContext;
2722 
2723   if (!IsMtrrSupported ()) {
2724     return MtrrSetting;
2725   }
2726 
2727   MtrrLibPreMtrrChange (&MtrrContext);
2728 
2729   //
2730   // Set fixed MTRRs
2731   //
2732   MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
2733 
2734   //
2735   // Set variable MTRRs
2736   //
2737   MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
2738 
2739   //
2740   // Set MTRR_DEF_TYPE value
2741   //
2742   AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
2743 
2744   MtrrLibPostMtrrChangeEnableCache (&MtrrContext);
2745 
2746   return MtrrSetting;
2747 }
2748 
2749 
2750 /**
2751   Checks if MTRR is supported.
2752 
2753   @retval TRUE  MTRR is supported.
2754   @retval FALSE MTRR is not supported.
2755 
2756 **/
2757 BOOLEAN
2758 EFIAPI
IsMtrrSupported(VOID)2759 IsMtrrSupported (
2760   VOID
2761   )
2762 {
2763   CPUID_VERSION_INFO_EDX    Edx;
2764   MSR_IA32_MTRRCAP_REGISTER MtrrCap;
2765 
2766   //
2767   // Check CPUID(1).EDX[12] for MTRR capability
2768   //
2769   AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &Edx.Uint32);
2770   if (Edx.Bits.MTRR == 0) {
2771     return FALSE;
2772   }
2773 
2774   //
2775   // Check number of variable MTRRs and fixed MTRRs existence.
2776   // If number of variable MTRRs is zero, or fixed MTRRs do not
2777   // exist, return false.
2778   //
2779   MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);
2780   if ((MtrrCap.Bits.VCNT == 0) || (MtrrCap.Bits.FIX == 0)) {
2781     return FALSE;
2782   }
2783   return TRUE;
2784 }
2785 
2786 
2787 /**
2788   Worker function prints all MTRRs for debugging.
2789 
2790   If MtrrSetting is not NULL, print MTRR settings from input MTRR
2791   settings buffer.
2792   If MtrrSetting is NULL, print MTRR settings from MTRRs.
2793 
2794   @param  MtrrSetting    A buffer holding all MTRRs content.
2795 **/
2796 VOID
MtrrDebugPrintAllMtrrsWorker(IN MTRR_SETTINGS * MtrrSetting)2797 MtrrDebugPrintAllMtrrsWorker (
2798   IN MTRR_SETTINGS    *MtrrSetting
2799   )
2800 {
2801   DEBUG_CODE (
2802     MTRR_SETTINGS     LocalMtrrs;
2803     MTRR_SETTINGS     *Mtrrs;
2804     UINTN             Index;
2805     UINTN             RangeCount;
2806     UINT64            MtrrValidBitsMask;
2807     UINT64            MtrrValidAddressMask;
2808     UINT32            VariableMtrrCount;
2809     BOOLEAN           ContainVariableMtrr;
2810     MTRR_MEMORY_RANGE Ranges[
2811       ARRAY_SIZE (mMtrrLibFixedMtrrTable) * sizeof (UINT64) + 2 * ARRAY_SIZE (Mtrrs->Variables.Mtrr) + 1
2812       ];
2813     MTRR_MEMORY_RANGE RawVariableRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)];
2814 
2815     if (!IsMtrrSupported ()) {
2816       return;
2817     }
2818 
2819     VariableMtrrCount = GetVariableMtrrCountWorker ();
2820 
2821     if (MtrrSetting != NULL) {
2822       Mtrrs = MtrrSetting;
2823     } else {
2824       MtrrGetAllMtrrs (&LocalMtrrs);
2825       Mtrrs = &LocalMtrrs;
2826     }
2827 
2828     //
2829     // Dump RAW MTRR contents
2830     //
2831     DEBUG ((DEBUG_CACHE, "MTRR Settings:\n"));
2832     DEBUG ((DEBUG_CACHE, "=============\n"));
2833     DEBUG ((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));
2834     for (Index = 0; Index < ARRAY_SIZE (mMtrrLibFixedMtrrTable); Index++) {
2835       DEBUG ((DEBUG_CACHE, "Fixed MTRR[%02d]   : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));
2836     }
2837     ContainVariableMtrr = FALSE;
2838     for (Index = 0; Index < VariableMtrrCount; Index++) {
2839       if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {
2840         //
2841         // If mask is not valid, then do not display range
2842         //
2843         continue;
2844       }
2845       ContainVariableMtrr = TRUE;
2846       DEBUG ((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
2847         Index,
2848         Mtrrs->Variables.Mtrr[Index].Base,
2849         Mtrrs->Variables.Mtrr[Index].Mask
2850         ));
2851     }
2852     if (!ContainVariableMtrr) {
2853       DEBUG ((DEBUG_CACHE, "Variable MTRR    : None.\n"));
2854     }
2855     DEBUG((DEBUG_CACHE, "\n"));
2856 
2857     //
2858     // Dump MTRR setting in ranges
2859     //
2860     DEBUG((DEBUG_CACHE, "Memory Ranges:\n"));
2861     DEBUG((DEBUG_CACHE, "====================================\n"));
2862     MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
2863     Ranges[0].BaseAddress = 0;
2864     Ranges[0].Length      = MtrrValidBitsMask + 1;
2865     Ranges[0].Type        = MtrrGetDefaultMemoryTypeWorker (Mtrrs);
2866     RangeCount = 1;
2867 
2868     MtrrLibGetRawVariableRanges (
2869       &Mtrrs->Variables, VariableMtrrCount,
2870       MtrrValidBitsMask, MtrrValidAddressMask, RawVariableRanges
2871       );
2872     MtrrLibApplyVariableMtrrs (
2873       RawVariableRanges, VariableMtrrCount,
2874       Ranges, ARRAY_SIZE (Ranges), &RangeCount
2875       );
2876 
2877     MtrrLibApplyFixedMtrrs (&Mtrrs->Fixed, Ranges, ARRAY_SIZE (Ranges), &RangeCount);
2878 
2879     for (Index = 0; Index < RangeCount; Index++) {
2880       DEBUG ((DEBUG_CACHE, "%a:%016lx-%016lx\n",
2881         mMtrrMemoryCacheTypeShortName[Ranges[Index].Type],
2882         Ranges[Index].BaseAddress, Ranges[Index].BaseAddress + Ranges[Index].Length - 1
2883         ));
2884     }
2885   );
2886 }
2887 
2888 /**
2889   This function prints all MTRRs for debugging.
2890 **/
2891 VOID
2892 EFIAPI
MtrrDebugPrintAllMtrrs(VOID)2893 MtrrDebugPrintAllMtrrs (
2894   VOID
2895   )
2896 {
2897   MtrrDebugPrintAllMtrrsWorker (NULL);
2898 }
2899