• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   MTRR setting library
3 
4   Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include <Base.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 //
24 // Context to save and restore when MTRRs are programmed
25 //
26 typedef struct {
27   UINTN    Cr4;
28   BOOLEAN  InterruptState;
29 } MTRR_CONTEXT;
30 
31 //
32 // This table defines the offset, base and length of the fixed MTRRs
33 //
34 CONST FIXED_MTRR  mMtrrLibFixedMtrrTable[] = {
35   {
36     MTRR_LIB_IA32_MTRR_FIX64K_00000,
37     0,
38     SIZE_64KB
39   },
40   {
41     MTRR_LIB_IA32_MTRR_FIX16K_80000,
42     0x80000,
43     SIZE_16KB
44   },
45   {
46     MTRR_LIB_IA32_MTRR_FIX16K_A0000,
47     0xA0000,
48     SIZE_16KB
49   },
50   {
51     MTRR_LIB_IA32_MTRR_FIX4K_C0000,
52     0xC0000,
53     SIZE_4KB
54   },
55   {
56     MTRR_LIB_IA32_MTRR_FIX4K_C8000,
57     0xC8000,
58     SIZE_4KB
59   },
60   {
61     MTRR_LIB_IA32_MTRR_FIX4K_D0000,
62     0xD0000,
63     SIZE_4KB
64   },
65   {
66     MTRR_LIB_IA32_MTRR_FIX4K_D8000,
67     0xD8000,
68     SIZE_4KB
69   },
70   {
71     MTRR_LIB_IA32_MTRR_FIX4K_E0000,
72     0xE0000,
73     SIZE_4KB
74   },
75   {
76     MTRR_LIB_IA32_MTRR_FIX4K_E8000,
77     0xE8000,
78     SIZE_4KB
79   },
80   {
81     MTRR_LIB_IA32_MTRR_FIX4K_F0000,
82     0xF0000,
83     SIZE_4KB
84   },
85   {
86     MTRR_LIB_IA32_MTRR_FIX4K_F8000,
87     0xF8000,
88     SIZE_4KB
89   }
90 };
91 
92 //
93 // Lookup table used to print MTRRs
94 //
95 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {
96   "UC",  // CacheUncacheable
97   "WC",  // CacheWriteCombining
98   "R*",  // Invalid
99   "R*",  // Invalid
100   "WT",  // CacheWriteThrough
101   "WP",  // CacheWriteProtected
102   "WB",  // CacheWriteBack
103   "R*"   // Invalid
104 };
105 
106 /**
107   Worker function returns the variable MTRR count for the CPU.
108 
109   @return Variable MTRR count
110 
111 **/
112 UINT32
GetVariableMtrrCountWorker(VOID)113 GetVariableMtrrCountWorker (
114   VOID
115   )
116 {
117   UINT32  VariableMtrrCount;
118 
119   VariableMtrrCount = (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);
120   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
121   return VariableMtrrCount;
122 }
123 
124 /**
125   Returns the variable MTRR count for the CPU.
126 
127   @return Variable MTRR count
128 
129 **/
130 UINT32
131 EFIAPI
GetVariableMtrrCount(VOID)132 GetVariableMtrrCount (
133   VOID
134   )
135 {
136   if (!IsMtrrSupported ()) {
137     return 0;
138   }
139   return GetVariableMtrrCountWorker ();
140 }
141 
142 /**
143   Worker function returns the firmware usable variable MTRR count for the CPU.
144 
145   @return Firmware usable variable MTRR count
146 
147 **/
148 UINT32
GetFirmwareVariableMtrrCountWorker(VOID)149 GetFirmwareVariableMtrrCountWorker (
150   VOID
151   )
152 {
153   UINT32  VariableMtrrCount;
154   UINT32  ReservedMtrrNumber;
155 
156   VariableMtrrCount = GetVariableMtrrCountWorker ();
157   ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
158   if (VariableMtrrCount < ReservedMtrrNumber) {
159     return 0;
160   }
161 
162   return VariableMtrrCount - ReservedMtrrNumber;
163 }
164 
165 /**
166   Returns the firmware usable variable MTRR count for the CPU.
167 
168   @return Firmware usable variable MTRR count
169 
170 **/
171 UINT32
172 EFIAPI
GetFirmwareVariableMtrrCount(VOID)173 GetFirmwareVariableMtrrCount (
174   VOID
175   )
176 {
177   if (!IsMtrrSupported ()) {
178     return 0;
179   }
180   return GetFirmwareVariableMtrrCountWorker ();
181 }
182 
183 /**
184   Worker function returns the default MTRR cache type for the system.
185 
186   If MtrrSetting is not NULL, returns the default MTRR cache type from input
187   MTRR settings buffer.
188   If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
189 
190   @param[in]  MtrrSetting    A buffer holding all MTRRs content.
191 
192   @return  The default MTRR cache type.
193 
194 **/
195 MTRR_MEMORY_CACHE_TYPE
MtrrGetDefaultMemoryTypeWorker(IN MTRR_SETTINGS * MtrrSetting)196 MtrrGetDefaultMemoryTypeWorker (
197   IN MTRR_SETTINGS      *MtrrSetting
198   )
199 {
200   if (MtrrSetting == NULL) {
201     return (MTRR_MEMORY_CACHE_TYPE) (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0x7);
202   } else {
203     return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7);
204   }
205 }
206 
207 
208 /**
209   Returns the default MTRR cache type for the system.
210 
211   @return  The default MTRR cache type.
212 
213 **/
214 MTRR_MEMORY_CACHE_TYPE
215 EFIAPI
MtrrGetDefaultMemoryType(VOID)216 MtrrGetDefaultMemoryType (
217   VOID
218   )
219 {
220   if (!IsMtrrSupported ()) {
221     return CacheUncacheable;
222   }
223   return MtrrGetDefaultMemoryTypeWorker (NULL);
224 }
225 
226 /**
227   Preparation before programming MTRR.
228 
229   This function will do some preparation for programming MTRRs:
230   disable cache, invalid cache and disable MTRR caching functionality
231 
232   @param[out] MtrrContext  Pointer to context to save
233 
234 **/
235 VOID
PreMtrrChange(OUT MTRR_CONTEXT * MtrrContext)236 PreMtrrChange (
237   OUT MTRR_CONTEXT  *MtrrContext
238   )
239 {
240   //
241   // Disable interrupts and save current interrupt state
242   //
243   MtrrContext->InterruptState = SaveAndDisableInterrupts();
244 
245   //
246   // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
247   //
248   AsmDisableCache ();
249 
250   //
251   // Save original CR4 value and clear PGE flag (Bit 7)
252   //
253   MtrrContext->Cr4 = AsmReadCr4 ();
254   AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));
255 
256   //
257   // Flush all TLBs
258   //
259   CpuFlushTlb ();
260 
261   //
262   // Disable MTRRs
263   //
264   AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);
265 }
266 
267 /**
268   Cleaning up after programming MTRRs.
269 
270   This function will do some clean up after programming MTRRs:
271   Flush all TLBs,  re-enable caching, restore CR4.
272 
273   @param[in] MtrrContext  Pointer to context to restore
274 
275 **/
276 VOID
PostMtrrChangeEnableCache(IN MTRR_CONTEXT * MtrrContext)277 PostMtrrChangeEnableCache (
278   IN MTRR_CONTEXT  *MtrrContext
279   )
280 {
281   //
282   // Flush all TLBs
283   //
284   CpuFlushTlb ();
285 
286   //
287   // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
288   //
289   AsmEnableCache ();
290 
291   //
292   // Restore original CR4 value
293   //
294   AsmWriteCr4 (MtrrContext->Cr4);
295 
296   //
297   // Restore original interrupt state
298   //
299   SetInterruptState (MtrrContext->InterruptState);
300 }
301 
302 /**
303   Cleaning up after programming MTRRs.
304 
305   This function will do some clean up after programming MTRRs:
306   enable MTRR caching functionality, and enable cache
307 
308   @param[in] MtrrContext  Pointer to context to restore
309 
310 **/
311 VOID
PostMtrrChange(IN MTRR_CONTEXT * MtrrContext)312 PostMtrrChange (
313   IN MTRR_CONTEXT  *MtrrContext
314   )
315 {
316   //
317   // Enable Cache MTRR
318   //
319   AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);
320 
321   PostMtrrChangeEnableCache (MtrrContext);
322 }
323 
324 /**
325   Worker function gets the content in fixed MTRRs
326 
327   @param[out]  FixedSettings  A buffer to hold fixed MTRRs content.
328 
329   @retval The pointer of FixedSettings
330 
331 **/
332 MTRR_FIXED_SETTINGS*
MtrrGetFixedMtrrWorker(OUT MTRR_FIXED_SETTINGS * FixedSettings)333 MtrrGetFixedMtrrWorker (
334   OUT MTRR_FIXED_SETTINGS         *FixedSettings
335   )
336 {
337   UINT32  Index;
338 
339   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
340       FixedSettings->Mtrr[Index] =
341         AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
342   }
343 
344   return FixedSettings;
345 }
346 
347 
348 /**
349   This function gets the content in fixed MTRRs
350 
351   @param[out]  FixedSettings  A buffer to hold fixed MTRRs content.
352 
353   @retval The pointer of FixedSettings
354 
355 **/
356 MTRR_FIXED_SETTINGS*
357 EFIAPI
MtrrGetFixedMtrr(OUT MTRR_FIXED_SETTINGS * FixedSettings)358 MtrrGetFixedMtrr (
359   OUT MTRR_FIXED_SETTINGS         *FixedSettings
360   )
361 {
362   if (!IsMtrrSupported ()) {
363     return FixedSettings;
364   }
365 
366   return MtrrGetFixedMtrrWorker (FixedSettings);
367 }
368 
369 
370 /**
371   Worker function will get the raw value in variable MTRRs
372 
373   If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
374   MTRR settings buffer.
375   If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
376 
377   @param[in]  MtrrSetting        A buffer holding all MTRRs content.
378   @param[in]  VariableMtrrCount  Number of variable MTRRs.
379   @param[out] VariableSettings   A buffer to hold variable MTRRs content.
380 
381   @return The VariableSettings input pointer
382 
383 **/
384 MTRR_VARIABLE_SETTINGS*
MtrrGetVariableMtrrWorker(IN MTRR_SETTINGS * MtrrSetting,IN UINT32 VariableMtrrCount,OUT MTRR_VARIABLE_SETTINGS * VariableSettings)385 MtrrGetVariableMtrrWorker (
386   IN  MTRR_SETTINGS           *MtrrSetting,
387   IN  UINT32                  VariableMtrrCount,
388   OUT MTRR_VARIABLE_SETTINGS  *VariableSettings
389   )
390 {
391   UINT32  Index;
392 
393   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
394 
395   for (Index = 0; Index < VariableMtrrCount; Index++) {
396     if (MtrrSetting == NULL) {
397       VariableSettings->Mtrr[Index].Base =
398         AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));
399       VariableSettings->Mtrr[Index].Mask =
400         AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);
401     } else {
402       VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;
403       VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;
404     }
405   }
406 
407   return  VariableSettings;
408 }
409 
410 /**
411   This function will get the raw value in variable MTRRs
412 
413   @param[out]  VariableSettings   A buffer to hold variable MTRRs content.
414 
415   @return The VariableSettings input pointer
416 
417 **/
418 MTRR_VARIABLE_SETTINGS*
419 EFIAPI
MtrrGetVariableMtrr(OUT MTRR_VARIABLE_SETTINGS * VariableSettings)420 MtrrGetVariableMtrr (
421   OUT MTRR_VARIABLE_SETTINGS         *VariableSettings
422   )
423 {
424   if (!IsMtrrSupported ()) {
425     return VariableSettings;
426   }
427 
428   return MtrrGetVariableMtrrWorker (
429            NULL,
430            GetVariableMtrrCountWorker (),
431            VariableSettings
432            );
433 }
434 
435 /**
436   Programs fixed MTRRs registers.
437 
438   @param[in]      MemoryCacheType  The memory type to set.
439   @param[in, out] Base             The base address of memory range.
440   @param[in, out] Length           The length of memory range.
441   @param[out]     ReturnMsrNum     The index of the fixed MTRR MSR to program.
442   @param[out]     ReturnClearMask  The bits to clear in the fixed MTRR MSR.
443   @param[out]     ReturnOrMask     The bits to set in the fixed MTRR MSR.
444 
445   @retval RETURN_SUCCESS      The cache type was updated successfully
446   @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid
447                               for the fixed MTRRs.
448 
449 **/
450 RETURN_STATUS
ProgramFixedMtrr(IN UINT64 MemoryCacheType,IN OUT UINT64 * Base,IN OUT UINT64 * Length,OUT UINT32 * ReturnMsrNum,OUT UINT64 * ReturnClearMask,OUT UINT64 * ReturnOrMask)451 ProgramFixedMtrr (
452   IN     UINT64               MemoryCacheType,
453   IN OUT UINT64               *Base,
454   IN OUT UINT64               *Length,
455   OUT    UINT32               *ReturnMsrNum,
456   OUT    UINT64               *ReturnClearMask,
457   OUT    UINT64               *ReturnOrMask
458   )
459 {
460   UINT32  MsrNum;
461   UINT32  ByteShift;
462   UINT64  TempQword;
463   UINT64  OrMask;
464   UINT64  ClearMask;
465 
466   TempQword = 0;
467   OrMask    = 0;
468   ClearMask = 0;
469 
470   for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {
471     if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&
472         (*Base <
473             (
474               mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
475               (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)
476             )
477           )
478         ) {
479       break;
480     }
481   }
482 
483   if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {
484     return RETURN_UNSUPPORTED;
485   }
486 
487   //
488   // We found the fixed MTRR to be programmed
489   //
490   for (ByteShift = 0; ByteShift < 8; ByteShift++) {
491     if (*Base ==
492          (
493            mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +
494            (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length)
495          )
496        ) {
497       break;
498     }
499   }
500 
501   if (ByteShift == 8) {
502     return RETURN_UNSUPPORTED;
503   }
504 
505   for (
506         ;
507         ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length));
508         ByteShift++
509       ) {
510     OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));
511     ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));
512     *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length;
513     *Base += mMtrrLibFixedMtrrTable[MsrNum].Length;
514   }
515 
516   if (ByteShift < 8 && (*Length != 0)) {
517     return RETURN_UNSUPPORTED;
518   }
519 
520   *ReturnMsrNum    = MsrNum;
521   *ReturnClearMask = ClearMask;
522   *ReturnOrMask    = OrMask;
523 
524   return RETURN_SUCCESS;
525 }
526 
527 
528 /**
529   Worker function gets the attribute of variable MTRRs.
530 
531   This function shadows the content of variable MTRRs into an
532   internal array: VariableMtrr.
533 
534   @param[in]   VariableSettings           The variable MTRR values to shadow
535   @param[in]   FirmwareVariableMtrrCount  The number of variable MTRRs available to firmware
536   @param[in]   MtrrValidBitsMask          The mask for the valid bit of the MTRR
537   @param[in]   MtrrValidAddressMask       The valid address mask for MTRR
538   @param[out]  VariableMtrr               The array to shadow variable MTRRs content
539 
540   @return                       The return value of this parameter indicates the
541                                 number of MTRRs which has been used.
542 
543 **/
544 UINT32
MtrrGetMemoryAttributeInVariableMtrrWorker(IN MTRR_VARIABLE_SETTINGS * VariableSettings,IN UINTN FirmwareVariableMtrrCount,IN UINT64 MtrrValidBitsMask,IN UINT64 MtrrValidAddressMask,OUT VARIABLE_MTRR * VariableMtrr)545 MtrrGetMemoryAttributeInVariableMtrrWorker (
546   IN  MTRR_VARIABLE_SETTINGS  *VariableSettings,
547   IN  UINTN                   FirmwareVariableMtrrCount,
548   IN  UINT64                  MtrrValidBitsMask,
549   IN  UINT64                  MtrrValidAddressMask,
550   OUT VARIABLE_MTRR           *VariableMtrr
551   )
552 {
553   UINTN   Index;
554   UINT32  UsedMtrr;
555 
556   ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);
557   for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) {
558     if ((VariableSettings->Mtrr[Index].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {
559       VariableMtrr[Index].Msr         = (UINT32)Index;
560       VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);
561       VariableMtrr[Index].Length      = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;
562       VariableMtrr[Index].Type        = (VariableSettings->Mtrr[Index].Base & 0x0ff);
563       VariableMtrr[Index].Valid       = TRUE;
564       VariableMtrr[Index].Used        = TRUE;
565       UsedMtrr++;
566     }
567   }
568   return UsedMtrr;
569 }
570 
571 
572 /**
573   Gets the attribute of variable MTRRs.
574 
575   This function shadows the content of variable MTRRs into an
576   internal array: VariableMtrr.
577 
578   @param[in]   MtrrValidBitsMask     The mask for the valid bit of the MTRR
579   @param[in]   MtrrValidAddressMask  The valid address mask for MTRR
580   @param[out]  VariableMtrr          The array to shadow variable MTRRs content
581 
582   @return                       The return value of this paramter indicates the
583                                 number of MTRRs which has been used.
584 
585 **/
586 UINT32
587 EFIAPI
MtrrGetMemoryAttributeInVariableMtrr(IN UINT64 MtrrValidBitsMask,IN UINT64 MtrrValidAddressMask,OUT VARIABLE_MTRR * VariableMtrr)588 MtrrGetMemoryAttributeInVariableMtrr (
589   IN  UINT64                    MtrrValidBitsMask,
590   IN  UINT64                    MtrrValidAddressMask,
591   OUT VARIABLE_MTRR             *VariableMtrr
592   )
593 {
594   MTRR_VARIABLE_SETTINGS  VariableSettings;
595 
596   if (!IsMtrrSupported ()) {
597     return 0;
598   }
599 
600   MtrrGetVariableMtrrWorker (
601     NULL,
602     GetVariableMtrrCountWorker (),
603     &VariableSettings
604     );
605 
606   return MtrrGetMemoryAttributeInVariableMtrrWorker (
607            &VariableSettings,
608            GetFirmwareVariableMtrrCountWorker (),
609            MtrrValidBitsMask,
610            MtrrValidAddressMask,
611            VariableMtrr
612            );
613 }
614 
615 
616 /**
617   Checks overlap between given memory range and MTRRs.
618 
619   @param[in]  FirmwareVariableMtrrCount  The number of variable MTRRs available
620                                          to firmware.
621   @param[in]  Start                      The start address of memory range.
622   @param[in]  End                        The end address of memory range.
623   @param[in]  VariableMtrr               The array to shadow variable MTRRs content
624 
625   @retval TRUE             Overlap exists.
626   @retval FALSE            No overlap.
627 
628 **/
629 BOOLEAN
CheckMemoryAttributeOverlap(IN UINTN FirmwareVariableMtrrCount,IN PHYSICAL_ADDRESS Start,IN PHYSICAL_ADDRESS End,IN VARIABLE_MTRR * VariableMtrr)630 CheckMemoryAttributeOverlap (
631   IN UINTN             FirmwareVariableMtrrCount,
632   IN PHYSICAL_ADDRESS  Start,
633   IN PHYSICAL_ADDRESS  End,
634   IN VARIABLE_MTRR     *VariableMtrr
635   )
636 {
637   UINT32  Index;
638 
639   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
640     if (
641          VariableMtrr[Index].Valid &&
642          !(
643            (Start > (VariableMtrr[Index].BaseAddress +
644                      VariableMtrr[Index].Length - 1)
645            ) ||
646            (End < VariableMtrr[Index].BaseAddress)
647          )
648        ) {
649       return TRUE;
650     }
651   }
652 
653   return FALSE;
654 }
655 
656 
657 /**
658   Marks a variable MTRR as non-valid.
659 
660   @param[in]   Index         The index of the array VariableMtrr to be invalidated
661   @param[in]   VariableMtrr  The array to shadow variable MTRRs content
662   @param[out]  UsedMtrr      The number of MTRRs which has already been used
663 
664 **/
665 VOID
InvalidateShadowMtrr(IN UINTN Index,IN VARIABLE_MTRR * VariableMtrr,OUT UINT32 * UsedMtrr)666 InvalidateShadowMtrr (
667   IN   UINTN              Index,
668   IN   VARIABLE_MTRR      *VariableMtrr,
669   OUT  UINT32             *UsedMtrr
670   )
671 {
672   VariableMtrr[Index].Valid = FALSE;
673   *UsedMtrr = *UsedMtrr - 1;
674 }
675 
676 
677 /**
678   Combines memory attributes.
679 
680   If overlap exists between given memory range and MTRRs, try to combine them.
681 
682   @param[in]       FirmwareVariableMtrrCount  The number of variable MTRRs
683                                               available to firmware.
684   @param[in]       Attributes                 The memory type to set.
685   @param[in, out]  Base                       The base address of memory range.
686   @param[in, out]  Length                     The length of memory range.
687   @param[in]       VariableMtrr               The array to shadow variable MTRRs content
688   @param[in, out]  UsedMtrr                   The number of MTRRs which has already been used
689   @param[out]      OverwriteExistingMtrr      Returns whether an existing MTRR was used
690 
691   @retval EFI_SUCCESS            Memory region successfully combined.
692   @retval EFI_ACCESS_DENIED      Memory region cannot be combined.
693 
694 **/
695 RETURN_STATUS
CombineMemoryAttribute(IN UINT32 FirmwareVariableMtrrCount,IN UINT64 Attributes,IN OUT UINT64 * Base,IN OUT UINT64 * Length,IN VARIABLE_MTRR * VariableMtrr,IN OUT UINT32 * UsedMtrr,OUT BOOLEAN * OverwriteExistingMtrr)696 CombineMemoryAttribute (
697   IN     UINT32             FirmwareVariableMtrrCount,
698   IN     UINT64             Attributes,
699   IN OUT UINT64             *Base,
700   IN OUT UINT64             *Length,
701   IN     VARIABLE_MTRR      *VariableMtrr,
702   IN OUT UINT32             *UsedMtrr,
703   OUT    BOOLEAN            *OverwriteExistingMtrr
704   )
705 {
706   UINT32  Index;
707   UINT64  CombineStart;
708   UINT64  CombineEnd;
709   UINT64  MtrrEnd;
710   UINT64  EndAddress;
711   BOOLEAN CoveredByExistingMtrr;
712 
713   *OverwriteExistingMtrr = FALSE;
714   CoveredByExistingMtrr = FALSE;
715   EndAddress = *Base +*Length - 1;
716 
717   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
718 
719     MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;
720     if (
721          !VariableMtrr[Index].Valid ||
722          (
723            *Base > (MtrrEnd) ||
724            (EndAddress < VariableMtrr[Index].BaseAddress)
725          )
726        ) {
727       continue;
728     }
729 
730     //
731     // Combine same attribute MTRR range
732     //
733     if (Attributes == VariableMtrr[Index].Type) {
734       //
735       // if the MTRR range contain the request range, set a flag, then continue to
736       // invalidate any MTRR of the same request range with higher priority cache type.
737       //
738       if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {
739         CoveredByExistingMtrr = TRUE;
740         continue;
741       }
742       //
743       // invalid this MTRR, and program the combine range
744       //
745       CombineStart  =
746         (*Base) < VariableMtrr[Index].BaseAddress ?
747           (*Base) :
748           VariableMtrr[Index].BaseAddress;
749       CombineEnd    = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;
750 
751       //
752       // Record the MTRR usage status in VariableMtrr array.
753       //
754       InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
755       *Base       = CombineStart;
756       *Length     = CombineEnd - CombineStart + 1;
757       EndAddress  = CombineEnd;
758       *OverwriteExistingMtrr = TRUE;
759       continue;
760     } else {
761       //
762       // The cache type is different, but the range is convered by one MTRR
763       //
764       if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {
765         InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
766         continue;
767       }
768 
769     }
770 
771     if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&
772          VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||
773         (Attributes == MTRR_CACHE_WRITE_BACK &&
774          VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||
775         (Attributes == MTRR_CACHE_UNCACHEABLE) ||
776         (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)
777      ) {
778       *OverwriteExistingMtrr = TRUE;
779       continue;
780     }
781     //
782     // Other type memory overlap is invalid
783     //
784     return RETURN_ACCESS_DENIED;
785   }
786 
787   if (CoveredByExistingMtrr) {
788     *Length = 0;
789   }
790 
791   return RETURN_SUCCESS;
792 }
793 
794 
795 /**
796   Calculates the maximum value which is a power of 2, but less the MemoryLength.
797 
798   @param[in]  MemoryLength        The number to pass in.
799 
800   @return The maximum value which is align to power of 2 and less the MemoryLength
801 
802 **/
803 UINT64
Power2MaxMemory(IN UINT64 MemoryLength)804 Power2MaxMemory (
805   IN UINT64                     MemoryLength
806   )
807 {
808   UINT64  Result;
809 
810   if (RShiftU64 (MemoryLength, 32) != 0) {
811     Result = LShiftU64 (
812                (UINT64) GetPowerOfTwo32 (
813                           (UINT32) RShiftU64 (MemoryLength, 32)
814                           ),
815                32
816                );
817   } else {
818     Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);
819   }
820 
821   return Result;
822 }
823 
824 
825 /**
826   Determines the MTRR numbers used to program a memory range.
827 
828   This function first checks the alignment of the base address.
829   If the alignment of the base address <= Length, cover the memory range
830  (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and
831   Length -= alignment. Repeat the step until alignment > Length.
832 
833   Then this function determines which direction of programming the variable
834   MTRRs for the remaining length will use fewer MTRRs.
835 
836   @param[in]  BaseAddress Length of Memory to program MTRR
837   @param[in]  Length      Length of Memory to program MTRR
838   @param[in]  MtrrNumber  Pointer to the number of necessary MTRRs
839 
840   @retval TRUE        Positive direction is better.
841           FALSE       Negative direction is better.
842 
843 **/
844 BOOLEAN
GetMtrrNumberAndDirection(IN UINT64 BaseAddress,IN UINT64 Length,IN UINTN * MtrrNumber)845 GetMtrrNumberAndDirection (
846   IN UINT64      BaseAddress,
847   IN UINT64      Length,
848   IN UINTN       *MtrrNumber
849   )
850 {
851   UINT64  TempQword;
852   UINT64  Alignment;
853   UINT32  Positive;
854   UINT32  Subtractive;
855 
856   *MtrrNumber = 0;
857 
858   if (BaseAddress != 0) {
859     do {
860       //
861       // Calculate the alignment of the base address.
862       //
863       Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
864 
865       if (Alignment > Length) {
866         break;
867       }
868 
869       (*MtrrNumber)++;
870       BaseAddress += Alignment;
871       Length -= Alignment;
872     } while (TRUE);
873 
874     if (Length == 0) {
875       return TRUE;
876     }
877   }
878 
879   TempQword   = Length;
880   Positive    = 0;
881   Subtractive = 0;
882 
883   do {
884     TempQword -= Power2MaxMemory (TempQword);
885     Positive++;
886   } while (TempQword != 0);
887 
888   TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;
889   Subtractive++;
890   do {
891     TempQword -= Power2MaxMemory (TempQword);
892     Subtractive++;
893   } while (TempQword != 0);
894 
895   if (Positive <= Subtractive) {
896     *MtrrNumber += Positive;
897     return TRUE;
898   } else {
899     *MtrrNumber += Subtractive;
900     return FALSE;
901   }
902 }
903 
904 /**
905   Invalid variable MTRRs according to the value in the shadow array.
906 
907   This function programs MTRRs according to the values specified
908   in the shadow array.
909 
910   @param[in, out]  VariableSettings   Variable MTRR settings
911   @param[in]       VariableMtrrCount  Number of variable MTRRs
912   @param[in, out]  VariableMtrr       Shadow of variable MTRR contents
913 
914 **/
915 VOID
InvalidateMtrr(IN OUT MTRR_VARIABLE_SETTINGS * VariableSettings,IN UINTN VariableMtrrCount,IN OUT VARIABLE_MTRR * VariableMtrr)916 InvalidateMtrr (
917   IN OUT MTRR_VARIABLE_SETTINGS  *VariableSettings,
918   IN     UINTN                   VariableMtrrCount,
919   IN OUT VARIABLE_MTRR           *VariableMtrr
920   )
921 {
922   UINTN         Index;
923 
924   for (Index = 0; Index < VariableMtrrCount; Index++) {
925     if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {
926        VariableSettings->Mtrr[Index].Base = 0;
927        VariableSettings->Mtrr[Index].Mask = 0;
928        VariableMtrr[Index].Used = FALSE;
929     }
930   }
931 }
932 
933 
934 /**
935   Programs variable MTRRs
936 
937   This function programs variable MTRRs
938 
939   @param[in, out]  VariableSettings      Variable MTRR settings.
940   @param[in]       MtrrNumber            Index of MTRR to program.
941   @param[in]       BaseAddress           Base address of memory region.
942   @param[in]       Length                Length of memory region.
943   @param[in]       MemoryCacheType       Memory type to set.
944   @param[in]       MtrrValidAddressMask  The valid address mask for MTRR
945 
946 **/
947 VOID
ProgramVariableMtrr(IN OUT MTRR_VARIABLE_SETTINGS * VariableSettings,IN UINTN MtrrNumber,IN PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN UINT64 MemoryCacheType,IN UINT64 MtrrValidAddressMask)948 ProgramVariableMtrr (
949   IN OUT MTRR_VARIABLE_SETTINGS  *VariableSettings,
950   IN     UINTN                   MtrrNumber,
951   IN     PHYSICAL_ADDRESS        BaseAddress,
952   IN     UINT64                  Length,
953   IN     UINT64                  MemoryCacheType,
954   IN     UINT64                  MtrrValidAddressMask
955   )
956 {
957   UINT64        TempQword;
958 
959   //
960   // MTRR Physical Base
961   //
962   TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;
963   VariableSettings->Mtrr[MtrrNumber].Base = TempQword;
964 
965   //
966   // MTRR Physical Mask
967   //
968   TempQword = ~(Length - 1);
969   VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED;
970 }
971 
972 
973 /**
974   Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.
975 
976   If MtrrSetting is not NULL, gets the default memory attribute from input
977   MTRR settings buffer.
978   If MtrrSetting is NULL, gets the default memory attribute from MSR.
979 
980   @param[in]  MtrrSetting        A buffer holding all MTRRs content.
981   @param[in]  MtrrType           MTRR memory type
982 
983   @return The enum item in MTRR_MEMORY_CACHE_TYPE
984 
985 **/
986 MTRR_MEMORY_CACHE_TYPE
GetMemoryCacheTypeFromMtrrType(IN MTRR_SETTINGS * MtrrSetting,IN UINT64 MtrrType)987 GetMemoryCacheTypeFromMtrrType (
988   IN MTRR_SETTINGS         *MtrrSetting,
989   IN UINT64                MtrrType
990   )
991 {
992   switch (MtrrType) {
993   case MTRR_CACHE_UNCACHEABLE:
994     return CacheUncacheable;
995   case MTRR_CACHE_WRITE_COMBINING:
996     return CacheWriteCombining;
997   case MTRR_CACHE_WRITE_THROUGH:
998     return CacheWriteThrough;
999   case MTRR_CACHE_WRITE_PROTECTED:
1000     return CacheWriteProtected;
1001   case MTRR_CACHE_WRITE_BACK:
1002     return CacheWriteBack;
1003   default:
1004     //
1005     // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
1006     // no MTRR covers the range
1007     //
1008     return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);
1009   }
1010 }
1011 
1012 /**
1013   Initializes the valid bits mask and valid address mask for MTRRs.
1014 
1015   This function initializes the valid bits mask and valid address mask for MTRRs.
1016 
1017   @param[out]  MtrrValidBitsMask     The mask for the valid bit of the MTRR
1018   @param[out]  MtrrValidAddressMask  The valid address mask for the MTRR
1019 
1020 **/
1021 VOID
MtrrLibInitializeMtrrMask(OUT UINT64 * MtrrValidBitsMask,OUT UINT64 * MtrrValidAddressMask)1022 MtrrLibInitializeMtrrMask (
1023   OUT UINT64 *MtrrValidBitsMask,
1024   OUT UINT64 *MtrrValidAddressMask
1025   )
1026 {
1027   UINT32  RegEax;
1028   UINT8   PhysicalAddressBits;
1029 
1030   AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
1031 
1032   if (RegEax >= 0x80000008) {
1033     AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
1034 
1035     PhysicalAddressBits = (UINT8) RegEax;
1036 
1037     *MtrrValidBitsMask    = LShiftU64 (1, PhysicalAddressBits) - 1;
1038     *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
1039   } else {
1040     *MtrrValidBitsMask    = MTRR_LIB_MSR_VALID_MASK;
1041     *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;
1042   }
1043 }
1044 
1045 
1046 /**
1047   Determines the real attribute of a memory range.
1048 
1049   This function is to arbitrate the real attribute of the memory when
1050   there are 2 MTRRs covers the same memory range.  For further details,
1051   please refer the IA32 Software Developer's Manual, Volume 3,
1052   Section 10.11.4.1.
1053 
1054   @param[in]  MtrrType1    The first kind of Memory type
1055   @param[in]  MtrrType2    The second kind of memory type
1056 
1057 **/
1058 UINT64
MtrrPrecedence(IN UINT64 MtrrType1,IN UINT64 MtrrType2)1059 MtrrPrecedence (
1060   IN UINT64    MtrrType1,
1061   IN UINT64    MtrrType2
1062   )
1063 {
1064   UINT64 MtrrType;
1065 
1066   MtrrType = MTRR_CACHE_INVALID_TYPE;
1067   switch (MtrrType1) {
1068   case MTRR_CACHE_UNCACHEABLE:
1069     MtrrType = MTRR_CACHE_UNCACHEABLE;
1070     break;
1071   case MTRR_CACHE_WRITE_COMBINING:
1072     if (
1073          MtrrType2==MTRR_CACHE_WRITE_COMBINING ||
1074          MtrrType2==MTRR_CACHE_UNCACHEABLE
1075        ) {
1076       MtrrType = MtrrType2;
1077     }
1078     break;
1079   case MTRR_CACHE_WRITE_THROUGH:
1080     if (
1081          MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
1082          MtrrType2==MTRR_CACHE_WRITE_BACK
1083        ) {
1084       MtrrType = MTRR_CACHE_WRITE_THROUGH;
1085     } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {
1086       MtrrType = MTRR_CACHE_UNCACHEABLE;
1087     }
1088     break;
1089   case MTRR_CACHE_WRITE_PROTECTED:
1090     if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||
1091         MtrrType2 == MTRR_CACHE_UNCACHEABLE) {
1092       MtrrType = MtrrType2;
1093     }
1094     break;
1095   case MTRR_CACHE_WRITE_BACK:
1096     if (
1097          MtrrType2== MTRR_CACHE_UNCACHEABLE ||
1098          MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
1099          MtrrType2== MTRR_CACHE_WRITE_BACK
1100        ) {
1101       MtrrType = MtrrType2;
1102     }
1103     break;
1104   case MTRR_CACHE_INVALID_TYPE:
1105     MtrrType = MtrrType2;
1106     break;
1107   default:
1108     break;
1109   }
1110 
1111   if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {
1112     MtrrType = MtrrType1;
1113   }
1114   return MtrrType;
1115 }
1116 
1117 /**
1118   Worker function will get the memory cache type of the specific address.
1119 
1120   If MtrrSetting is not NULL, gets the memory cache type from input
1121   MTRR settings buffer.
1122   If MtrrSetting is NULL, gets the memory cache type from MTRRs.
1123 
1124   @param[in]  MtrrSetting        A buffer holding all MTRRs content.
1125   @param[in]  Address            The specific address
1126 
1127   @return Memory cache type of the specific address
1128 
1129 **/
1130 MTRR_MEMORY_CACHE_TYPE
MtrrGetMemoryAttributeByAddressWorker(IN MTRR_SETTINGS * MtrrSetting,IN PHYSICAL_ADDRESS Address)1131 MtrrGetMemoryAttributeByAddressWorker (
1132   IN MTRR_SETTINGS      *MtrrSetting,
1133   IN PHYSICAL_ADDRESS   Address
1134   )
1135 {
1136   UINT64                  TempQword;
1137   UINTN                   Index;
1138   UINTN                   SubIndex;
1139   UINT64                  MtrrType;
1140   UINT64                  TempMtrrType;
1141   MTRR_MEMORY_CACHE_TYPE  CacheType;
1142   VARIABLE_MTRR           VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1143   UINT64                  MtrrValidBitsMask;
1144   UINT64                  MtrrValidAddressMask;
1145   UINTN                   VariableMtrrCount;
1146   MTRR_VARIABLE_SETTINGS  VariableSettings;
1147 
1148   //
1149   // Check if MTRR is enabled, if not, return UC as attribute
1150   //
1151   if (MtrrSetting == NULL) {
1152     TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
1153   } else {
1154     TempQword = MtrrSetting->MtrrDefType;
1155   }
1156   MtrrType = MTRR_CACHE_INVALID_TYPE;
1157 
1158   if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1159     return CacheUncacheable;
1160   }
1161 
1162   //
1163   // If address is less than 1M, then try to go through the fixed MTRR
1164   //
1165   if (Address < BASE_1MB) {
1166     if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {
1167       //
1168       // Go through the fixed MTRR
1169       //
1170       for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1171          if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&
1172              Address  < (
1173                           mMtrrLibFixedMtrrTable[Index].BaseAddress +
1174                           (mMtrrLibFixedMtrrTable[Index].Length * 8)
1175                         )
1176             ) {
1177            SubIndex =
1178              ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /
1179                mMtrrLibFixedMtrrTable[Index].Length;
1180            if (MtrrSetting == NULL) {
1181              TempQword = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
1182            } else {
1183              TempQword = MtrrSetting->Fixed.Mtrr[Index];
1184            }
1185            MtrrType =  RShiftU64 (TempQword, SubIndex * 8) & 0xFF;
1186            return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);
1187          }
1188       }
1189     }
1190   }
1191   MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
1192 
1193   MtrrGetVariableMtrrWorker (
1194     MtrrSetting,
1195     GetVariableMtrrCountWorker (),
1196     &VariableSettings
1197     );
1198 
1199   MtrrGetMemoryAttributeInVariableMtrrWorker (
1200            &VariableSettings,
1201            GetFirmwareVariableMtrrCountWorker (),
1202            MtrrValidBitsMask,
1203            MtrrValidAddressMask,
1204            VariableMtrr
1205            );
1206 
1207   //
1208   // Go through the variable MTRR
1209   //
1210   VariableMtrrCount = GetVariableMtrrCountWorker ();
1211   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1212 
1213   for (Index = 0; Index < VariableMtrrCount; Index++) {
1214     if (VariableMtrr[Index].Valid) {
1215       if (Address >= VariableMtrr[Index].BaseAddress &&
1216           Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {
1217         TempMtrrType = VariableMtrr[Index].Type;
1218         MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);
1219       }
1220     }
1221   }
1222   CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);
1223 
1224   return CacheType;
1225 }
1226 
1227 
1228 /**
1229   This function will get the memory cache type of the specific address.
1230 
1231   This function is mainly for debug purpose.
1232 
1233   @param[in]  Address   The specific address
1234 
1235   @return Memory cache type of the specific address
1236 
1237 **/
1238 MTRR_MEMORY_CACHE_TYPE
1239 EFIAPI
MtrrGetMemoryAttribute(IN PHYSICAL_ADDRESS Address)1240 MtrrGetMemoryAttribute (
1241   IN PHYSICAL_ADDRESS   Address
1242   )
1243 {
1244   if (!IsMtrrSupported ()) {
1245     return CacheUncacheable;
1246   }
1247 
1248   return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);
1249 }
1250 
1251 /**
1252   Worker function prints all MTRRs for debugging.
1253 
1254   If MtrrSetting is not NULL, print MTRR settings from from input MTRR
1255   settings buffer.
1256   If MtrrSetting is NULL, print MTRR settings from MTRRs.
1257 
1258   @param  MtrrSetting    A buffer holding all MTRRs content.
1259 **/
1260 VOID
MtrrDebugPrintAllMtrrsWorker(IN MTRR_SETTINGS * MtrrSetting)1261 MtrrDebugPrintAllMtrrsWorker (
1262   IN MTRR_SETTINGS    *MtrrSetting
1263   )
1264 {
1265   DEBUG_CODE (
1266     MTRR_SETTINGS  LocalMtrrs;
1267     MTRR_SETTINGS  *Mtrrs;
1268     UINTN          Index;
1269     UINTN          Index1;
1270     UINTN          VariableMtrrCount;
1271     UINT64         Base;
1272     UINT64         Limit;
1273     UINT64         MtrrBase;
1274     UINT64         MtrrLimit;
1275     UINT64         RangeBase;
1276     UINT64         RangeLimit;
1277     UINT64         NoRangeBase;
1278     UINT64         NoRangeLimit;
1279     UINT32         RegEax;
1280     UINTN          MemoryType;
1281     UINTN          PreviousMemoryType;
1282     BOOLEAN        Found;
1283 
1284     if (!IsMtrrSupported ()) {
1285       return;
1286     }
1287 
1288     DEBUG((DEBUG_CACHE, "MTRR Settings\n"));
1289     DEBUG((DEBUG_CACHE, "=============\n"));
1290 
1291     if (MtrrSetting != NULL) {
1292       Mtrrs = MtrrSetting;
1293     } else {
1294       MtrrGetAllMtrrs (&LocalMtrrs);
1295       Mtrrs = &LocalMtrrs;
1296     }
1297 
1298     DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));
1299     for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1300       DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d]   : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));
1301     }
1302 
1303     VariableMtrrCount = GetVariableMtrrCount ();
1304     for (Index = 0; Index < VariableMtrrCount; Index++) {
1305       DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
1306         Index,
1307         Mtrrs->Variables.Mtrr[Index].Base,
1308         Mtrrs->Variables.Mtrr[Index].Mask
1309         ));
1310     }
1311     DEBUG((DEBUG_CACHE, "\n"));
1312     DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));
1313     DEBUG((DEBUG_CACHE, "====================================\n"));
1314 
1315     Base = 0;
1316     PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1317     for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1318       Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;
1319       for (Index1 = 0; Index1 < 8; Index1++) {
1320       MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);
1321         if (MemoryType > CacheWriteBack) {
1322           MemoryType = MTRR_CACHE_INVALID_TYPE;
1323         }
1324         if (MemoryType != PreviousMemoryType) {
1325           if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1326             DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1327           }
1328           PreviousMemoryType = MemoryType;
1329           DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1330         }
1331         Base += mMtrrLibFixedMtrrTable[Index].Length;
1332       }
1333     }
1334     DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1335 
1336     VariableMtrrCount = GetVariableMtrrCount ();
1337 
1338     Limit        = BIT36 - 1;
1339     AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
1340     if (RegEax >= 0x80000008) {
1341       AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
1342       Limit = LShiftU64 (1, RegEax & 0xff) - 1;
1343     }
1344     Base = BASE_1MB;
1345     PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;
1346     do {
1347       MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);
1348       if (MemoryType > CacheWriteBack) {
1349         MemoryType = MTRR_CACHE_INVALID_TYPE;
1350       }
1351 
1352       if (MemoryType != PreviousMemoryType) {
1353         if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {
1354           DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));
1355         }
1356         PreviousMemoryType = MemoryType;
1357         DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));
1358       }
1359 
1360       RangeBase    = BASE_1MB;
1361       NoRangeBase  = BASE_1MB;
1362       RangeLimit   = Limit;
1363       NoRangeLimit = Limit;
1364 
1365       for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {
1366         if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {
1367           //
1368           // If mask is not valid, then do not display range
1369           //
1370           continue;
1371         }
1372         MtrrBase  = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));
1373         MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);
1374 
1375         if (Base >= MtrrBase && Base < MtrrLimit) {
1376           Found = TRUE;
1377         }
1378 
1379         if (Base >= MtrrBase && MtrrBase > RangeBase) {
1380           RangeBase = MtrrBase;
1381         }
1382         if (Base > MtrrLimit && MtrrLimit > RangeBase) {
1383           RangeBase = MtrrLimit + 1;
1384         }
1385         if (Base < MtrrBase && MtrrBase < RangeLimit) {
1386           RangeLimit = MtrrBase - 1;
1387         }
1388         if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {
1389           RangeLimit = MtrrLimit;
1390         }
1391 
1392         if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {
1393           NoRangeBase = MtrrLimit + 1;
1394         }
1395         if (Base < MtrrBase && NoRangeLimit > MtrrBase) {
1396           NoRangeLimit = MtrrBase - 1;
1397         }
1398       }
1399 
1400       if (Found) {
1401         Base = RangeLimit + 1;
1402       } else {
1403         Base = NoRangeLimit + 1;
1404       }
1405     } while (Base < Limit);
1406     DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));
1407   );
1408 }
1409 
1410 
1411 /**
1412   This function prints all MTRRs for debugging.
1413 **/
1414 VOID
1415 EFIAPI
MtrrDebugPrintAllMtrrs(VOID)1416 MtrrDebugPrintAllMtrrs (
1417   VOID
1418   )
1419 {
1420   MtrrDebugPrintAllMtrrsWorker (NULL);
1421 }
1422 
1423 
1424 /**
1425   Worker function attempts to set the attributes for a memory range.
1426 
1427   If MtrrSettings is not NULL, set the attributes into the input MTRR
1428   settings buffer.
1429   If MtrrSettings is NULL, set the attributes into MTRRs registers.
1430 
1431   @param[in, out]  MtrrSetting       A buffer holding all MTRRs content.
1432   @param[in]       BaseAddress       The physical address that is the start
1433                                      address of a memory region.
1434   @param[in]       Length            The size in bytes of the memory region.
1435   @param[in]       Attribute         The bit mask of attributes to set for the
1436                                      memory region.
1437 
1438   @retval RETURN_SUCCESS            The attributes were set for the memory
1439                                     region.
1440   @retval RETURN_INVALID_PARAMETER  Length is zero.
1441   @retval RETURN_UNSUPPORTED        The processor does not support one or
1442                                     more bytes of the memory resource range
1443                                     specified by BaseAddress and Length.
1444   @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support
1445                                     for the memory resource range specified
1446                                     by BaseAddress and Length.
1447   @retval RETURN_ACCESS_DENIED      The attributes for the memory resource
1448                                     range specified by BaseAddress and Length
1449                                     cannot be modified.
1450   @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to
1451                                     modify the attributes of the memory
1452                                     resource range.
1453 
1454 **/
1455 RETURN_STATUS
MtrrSetMemoryAttributeWorker(IN OUT MTRR_SETTINGS * MtrrSetting,IN PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN MTRR_MEMORY_CACHE_TYPE Attribute)1456 MtrrSetMemoryAttributeWorker (
1457   IN OUT MTRR_SETTINGS           *MtrrSetting,
1458   IN PHYSICAL_ADDRESS            BaseAddress,
1459   IN UINT64                      Length,
1460   IN MTRR_MEMORY_CACHE_TYPE      Attribute
1461   )
1462 {
1463   UINT64                    TempQword;
1464   RETURN_STATUS             Status;
1465   UINT64                    MemoryType;
1466   UINT64                    Alignment;
1467   BOOLEAN                   OverLap;
1468   BOOLEAN                   Positive;
1469   UINT32                    MsrNum;
1470   UINTN                     MtrrNumber;
1471   VARIABLE_MTRR             VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1472   UINT32                    UsedMtrr;
1473   UINT64                    MtrrValidBitsMask;
1474   UINT64                    MtrrValidAddressMask;
1475   BOOLEAN                   OverwriteExistingMtrr;
1476   UINT32                    FirmwareVariableMtrrCount;
1477   MTRR_CONTEXT              MtrrContext;
1478   BOOLEAN                   MtrrContextValid;
1479   BOOLEAN                   FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];
1480   BOOLEAN                   FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];
1481   MTRR_FIXED_SETTINGS       WorkingFixedSettings;
1482   UINT32                    VariableMtrrCount;
1483   MTRR_VARIABLE_SETTINGS    OriginalVariableSettings;
1484   BOOLEAN                   ProgramVariableSettings;
1485   MTRR_VARIABLE_SETTINGS    WorkingVariableSettings;
1486   UINT32                    Index;
1487   UINT64                    ClearMask;
1488   UINT64                    OrMask;
1489   UINT64                    NewValue;
1490   MTRR_VARIABLE_SETTINGS    *VariableSettings;
1491 
1492   MtrrContextValid  = FALSE;
1493   VariableMtrrCount = 0;
1494   ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));
1495   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1496     FixedSettingsValid[Index]    = FALSE;
1497     FixedSettingsModified[Index] = FALSE;
1498   }
1499   ProgramVariableSettings = FALSE;
1500 
1501   if (!IsMtrrSupported ()) {
1502     Status = RETURN_UNSUPPORTED;
1503     goto Done;
1504   }
1505 
1506   MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
1507 
1508   TempQword = 0;
1509   MemoryType = (UINT64)Attribute;
1510   OverwriteExistingMtrr = FALSE;
1511 
1512   //
1513   // Check for an invalid parameter
1514   //
1515   if (Length == 0) {
1516     Status = RETURN_INVALID_PARAMETER;
1517     goto Done;
1518   }
1519 
1520   if (
1521        (BaseAddress & ~MtrrValidAddressMask) != 0 ||
1522        (Length & ~MtrrValidAddressMask) != 0
1523      ) {
1524     Status = RETURN_UNSUPPORTED;
1525     goto Done;
1526   }
1527 
1528   //
1529   // Check if Fixed MTRR
1530   //
1531   Status = RETURN_SUCCESS;
1532   if (BaseAddress < BASE_1MB) {
1533     while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {
1534       Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);
1535       if (RETURN_ERROR (Status)) {
1536         goto Done;
1537       }
1538       if (MtrrSetting != NULL) {
1539         MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask;
1540         MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED;
1541       } else {
1542         if (!FixedSettingsValid[MsrNum]) {
1543           WorkingFixedSettings.Mtrr[MsrNum] = AsmReadMsr64 (mMtrrLibFixedMtrrTable[MsrNum].Msr);
1544           FixedSettingsValid[MsrNum] = TRUE;
1545         }
1546         NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;
1547         if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {
1548           WorkingFixedSettings.Mtrr[MsrNum] = NewValue;
1549           FixedSettingsModified[MsrNum] = TRUE;
1550         }
1551       }
1552     }
1553 
1554     if (Length == 0) {
1555       //
1556       // A Length of 0 can only make sense for fixed MTTR ranges.
1557       // Since we just handled the fixed MTRRs, we can skip the
1558       // variable MTRR section.
1559       //
1560       goto Done;
1561     }
1562   }
1563 
1564   //
1565   // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
1566   // we can set the base to 0 to save variable MTRRs.
1567   //
1568   if (BaseAddress == BASE_1MB) {
1569     BaseAddress = 0;
1570     Length += SIZE_1MB;
1571   }
1572 
1573   //
1574   // Read all variable MTRRs
1575   //
1576   VariableMtrrCount = GetVariableMtrrCountWorker ();
1577   FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();
1578   if (MtrrSetting != NULL) {
1579     VariableSettings = &MtrrSetting->Variables;
1580   } else {
1581     MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings);
1582     CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));
1583     ProgramVariableSettings = TRUE;
1584     VariableSettings = &WorkingVariableSettings;
1585   }
1586 
1587   //
1588   // Check for overlap
1589   //
1590   UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (
1591                VariableSettings,
1592                FirmwareVariableMtrrCount,
1593                MtrrValidBitsMask,
1594                MtrrValidAddressMask,
1595                VariableMtrr
1596                );
1597   OverLap = CheckMemoryAttributeOverlap (
1598               FirmwareVariableMtrrCount,
1599               BaseAddress,
1600               BaseAddress + Length - 1,
1601               VariableMtrr
1602               );
1603   if (OverLap) {
1604     Status = CombineMemoryAttribute (
1605                FirmwareVariableMtrrCount,
1606                MemoryType,
1607                &BaseAddress,
1608                &Length,
1609                VariableMtrr,
1610                &UsedMtrr,
1611                &OverwriteExistingMtrr
1612                );
1613     if (RETURN_ERROR (Status)) {
1614       goto Done;
1615     }
1616 
1617     if (Length == 0) {
1618       //
1619       // Combined successfully, invalidate the now-unused MTRRs
1620       //
1621       InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
1622       Status = RETURN_SUCCESS;
1623       goto Done;
1624     }
1625   }
1626 
1627   //
1628   // The memory type is the same with the type specified by
1629   // MTRR_LIB_IA32_MTRR_DEF_TYPE.
1630   //
1631   if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryTypeWorker (MtrrSetting))) {
1632     //
1633     // Invalidate the now-unused MTRRs
1634     //
1635     InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
1636     goto Done;
1637   }
1638 
1639   Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);
1640 
1641   if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {
1642     Status = RETURN_OUT_OF_RESOURCES;
1643     goto Done;
1644   }
1645 
1646   //
1647   // Invalidate the now-unused MTRRs
1648   //
1649   InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);
1650 
1651   //
1652   // Find first unused MTRR
1653   //
1654   for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {
1655     if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1656       break;
1657     }
1658   }
1659 
1660   if (BaseAddress != 0) {
1661     do {
1662       //
1663       // Calculate the alignment of the base address.
1664       //
1665       Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));
1666 
1667       if (Alignment > Length) {
1668         break;
1669       }
1670 
1671       //
1672       // Find unused MTRR
1673       //
1674       for (; MsrNum < VariableMtrrCount; MsrNum++) {
1675         if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1676           break;
1677         }
1678       }
1679 
1680       ProgramVariableMtrr (
1681         VariableSettings,
1682         MsrNum,
1683         BaseAddress,
1684         Alignment,
1685         MemoryType,
1686         MtrrValidAddressMask
1687         );
1688       BaseAddress += Alignment;
1689       Length -= Alignment;
1690     } while (TRUE);
1691 
1692     if (Length == 0) {
1693       goto Done;
1694     }
1695   }
1696 
1697   TempQword = Length;
1698 
1699   if (!Positive) {
1700     Length = Power2MaxMemory (LShiftU64 (TempQword, 1));
1701 
1702     //
1703     // Find unused MTRR
1704     //
1705     for (; MsrNum < VariableMtrrCount; MsrNum++) {
1706       if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1707         break;
1708       }
1709     }
1710 
1711     ProgramVariableMtrr (
1712       VariableSettings,
1713       MsrNum,
1714       BaseAddress,
1715       Length,
1716       MemoryType,
1717       MtrrValidAddressMask
1718       );
1719     BaseAddress += Length;
1720     TempQword   = Length - TempQword;
1721     MemoryType  = MTRR_CACHE_UNCACHEABLE;
1722   }
1723 
1724   do {
1725     //
1726     // Find unused MTRR
1727     //
1728     for (; MsrNum < VariableMtrrCount; MsrNum++) {
1729       if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1730         break;
1731       }
1732     }
1733 
1734     Length = Power2MaxMemory (TempQword);
1735     if (!Positive) {
1736       BaseAddress -= Length;
1737     }
1738 
1739     ProgramVariableMtrr (
1740       VariableSettings,
1741       MsrNum,
1742       BaseAddress,
1743       Length,
1744       MemoryType,
1745       MtrrValidAddressMask
1746       );
1747 
1748     if (Positive) {
1749       BaseAddress += Length;
1750     }
1751     TempQword -= Length;
1752 
1753   } while (TempQword > 0);
1754 
1755 Done:
1756 
1757   //
1758   // Write fixed MTRRs that have been modified
1759   //
1760   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1761     if (FixedSettingsModified[Index]) {
1762       if (!MtrrContextValid) {
1763         PreMtrrChange (&MtrrContext);
1764         MtrrContextValid = TRUE;
1765       }
1766       AsmWriteMsr64 (
1767         mMtrrLibFixedMtrrTable[Index].Msr,
1768         WorkingFixedSettings.Mtrr[Index]
1769         );
1770     }
1771   }
1772 
1773   //
1774   // Write variable MTRRs
1775   //
1776   if (ProgramVariableSettings) {
1777     for (Index = 0; Index < VariableMtrrCount; Index++) {
1778       if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||
1779           WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask    ) {
1780         if (!MtrrContextValid) {
1781           PreMtrrChange (&MtrrContext);
1782           MtrrContextValid = TRUE;
1783         }
1784         AsmWriteMsr64 (
1785           MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),
1786           WorkingVariableSettings.Mtrr[Index].Base
1787           );
1788         AsmWriteMsr64 (
1789           MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,
1790           WorkingVariableSettings.Mtrr[Index].Mask
1791           );
1792       }
1793     }
1794   }
1795   if (MtrrContextValid) {
1796     PostMtrrChange (&MtrrContext);
1797   }
1798 
1799   DEBUG((DEBUG_CACHE, "  Status = %r\n", Status));
1800   if (!RETURN_ERROR (Status)) {
1801     if (MtrrSetting != NULL) {
1802       MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED;
1803     }
1804     MtrrDebugPrintAllMtrrsWorker (MtrrSetting);
1805   }
1806 
1807   return Status;
1808 }
1809 
1810 /**
1811   This function attempts to set the attributes for a memory range.
1812 
1813   @param[in]  BaseAddress        The physical address that is the start
1814                                  address of a memory region.
1815   @param[in]  Length             The size in bytes of the memory region.
1816   @param[in]  Attributes         The bit mask of attributes to set for the
1817                                  memory region.
1818 
1819   @retval RETURN_SUCCESS            The attributes were set for the memory
1820                                     region.
1821   @retval RETURN_INVALID_PARAMETER  Length is zero.
1822   @retval RETURN_UNSUPPORTED        The processor does not support one or
1823                                     more bytes of the memory resource range
1824                                     specified by BaseAddress and Length.
1825   @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support
1826                                     for the memory resource range specified
1827                                     by BaseAddress and Length.
1828   @retval RETURN_ACCESS_DENIED      The attributes for the memory resource
1829                                     range specified by BaseAddress and Length
1830                                     cannot be modified.
1831   @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to
1832                                     modify the attributes of the memory
1833                                     resource range.
1834 
1835 **/
1836 RETURN_STATUS
1837 EFIAPI
MtrrSetMemoryAttribute(IN PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN MTRR_MEMORY_CACHE_TYPE Attribute)1838 MtrrSetMemoryAttribute (
1839   IN PHYSICAL_ADDRESS        BaseAddress,
1840   IN UINT64                  Length,
1841   IN MTRR_MEMORY_CACHE_TYPE  Attribute
1842   )
1843 {
1844   DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));
1845   return MtrrSetMemoryAttributeWorker (
1846            NULL,
1847            BaseAddress,
1848            Length,
1849            Attribute
1850            );
1851 }
1852 
1853 /**
1854   This function attempts to set the attributes into MTRR setting buffer for a memory range.
1855 
1856   @param[in, out]  MtrrSetting  MTRR setting buffer to be set.
1857   @param[in]       BaseAddress  The physical address that is the start address
1858                                 of a memory region.
1859   @param[in]       Length       The size in bytes of the memory region.
1860   @param[in]       Attribute    The bit mask of attributes to set for the
1861                                 memory region.
1862 
1863   @retval RETURN_SUCCESS            The attributes were set for the memory region.
1864   @retval RETURN_INVALID_PARAMETER  Length is zero.
1865   @retval RETURN_UNSUPPORTED        The processor does not support one or more bytes of the
1866                                     memory resource range specified by BaseAddress and Length.
1867   @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support for the memory resource
1868                                     range specified by BaseAddress and Length.
1869   @retval RETURN_ACCESS_DENIED      The attributes for the memory resource range specified by
1870                                     BaseAddress and Length cannot be modified.
1871   @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to modify the attributes of
1872                                     the memory resource range.
1873 
1874 **/
1875 RETURN_STATUS
1876 EFIAPI
MtrrSetMemoryAttributeInMtrrSettings(IN OUT MTRR_SETTINGS * MtrrSetting,IN PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN MTRR_MEMORY_CACHE_TYPE Attribute)1877 MtrrSetMemoryAttributeInMtrrSettings (
1878   IN OUT MTRR_SETTINGS       *MtrrSetting,
1879   IN PHYSICAL_ADDRESS        BaseAddress,
1880   IN UINT64                  Length,
1881   IN MTRR_MEMORY_CACHE_TYPE  Attribute
1882   )
1883 {
1884   DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));
1885   return MtrrSetMemoryAttributeWorker (
1886            MtrrSetting,
1887            BaseAddress,
1888            Length,
1889            Attribute
1890            );
1891 }
1892 
1893 /**
1894   Worker function setting variable MTRRs
1895 
1896   @param[in]  VariableSettings   A buffer to hold variable MTRRs content.
1897 
1898 **/
1899 VOID
MtrrSetVariableMtrrWorker(IN MTRR_VARIABLE_SETTINGS * VariableSettings)1900 MtrrSetVariableMtrrWorker (
1901   IN MTRR_VARIABLE_SETTINGS         *VariableSettings
1902   )
1903 {
1904   UINT32  Index;
1905   UINT32  VariableMtrrCount;
1906 
1907   VariableMtrrCount = GetVariableMtrrCountWorker ();
1908   ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1909 
1910   for (Index = 0; Index < VariableMtrrCount; Index++) {
1911     AsmWriteMsr64 (
1912       MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),
1913       VariableSettings->Mtrr[Index].Base
1914       );
1915     AsmWriteMsr64 (
1916       MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,
1917       VariableSettings->Mtrr[Index].Mask
1918       );
1919   }
1920 }
1921 
1922 
1923 /**
1924   This function sets variable MTRRs
1925 
1926   @param[in]  VariableSettings   A buffer to hold variable MTRRs content.
1927 
1928   @return The pointer of VariableSettings
1929 
1930 **/
1931 MTRR_VARIABLE_SETTINGS*
1932 EFIAPI
MtrrSetVariableMtrr(IN MTRR_VARIABLE_SETTINGS * VariableSettings)1933 MtrrSetVariableMtrr (
1934   IN MTRR_VARIABLE_SETTINGS         *VariableSettings
1935   )
1936 {
1937   MTRR_CONTEXT  MtrrContext;
1938 
1939   if (!IsMtrrSupported ()) {
1940     return VariableSettings;
1941   }
1942 
1943   PreMtrrChange (&MtrrContext);
1944   MtrrSetVariableMtrrWorker (VariableSettings);
1945   PostMtrrChange (&MtrrContext);
1946   MtrrDebugPrintAllMtrrs ();
1947 
1948   return  VariableSettings;
1949 }
1950 
1951 /**
1952   Worker function setting fixed MTRRs
1953 
1954   @param[in]  FixedSettings  A buffer to hold fixed MTRRs content.
1955 
1956 **/
1957 VOID
MtrrSetFixedMtrrWorker(IN MTRR_FIXED_SETTINGS * FixedSettings)1958 MtrrSetFixedMtrrWorker (
1959   IN MTRR_FIXED_SETTINGS          *FixedSettings
1960   )
1961 {
1962   UINT32  Index;
1963 
1964   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1965      AsmWriteMsr64 (
1966        mMtrrLibFixedMtrrTable[Index].Msr,
1967        FixedSettings->Mtrr[Index]
1968        );
1969   }
1970 }
1971 
1972 
1973 /**
1974   This function sets fixed MTRRs
1975 
1976   @param[in]  FixedSettings  A buffer to hold fixed MTRRs content.
1977 
1978   @retval The pointer of FixedSettings
1979 
1980 **/
1981 MTRR_FIXED_SETTINGS*
1982 EFIAPI
MtrrSetFixedMtrr(IN MTRR_FIXED_SETTINGS * FixedSettings)1983 MtrrSetFixedMtrr (
1984   IN MTRR_FIXED_SETTINGS          *FixedSettings
1985   )
1986 {
1987   MTRR_CONTEXT  MtrrContext;
1988 
1989   if (!IsMtrrSupported ()) {
1990     return FixedSettings;
1991   }
1992 
1993   PreMtrrChange (&MtrrContext);
1994   MtrrSetFixedMtrrWorker (FixedSettings);
1995   PostMtrrChange (&MtrrContext);
1996   MtrrDebugPrintAllMtrrs ();
1997 
1998   return FixedSettings;
1999 }
2000 
2001 
2002 /**
2003   This function gets the content in all MTRRs (variable and fixed)
2004 
2005   @param[out]  MtrrSetting  A buffer to hold all MTRRs content.
2006 
2007   @retval the pointer of MtrrSetting
2008 
2009 **/
2010 MTRR_SETTINGS *
2011 EFIAPI
MtrrGetAllMtrrs(OUT MTRR_SETTINGS * MtrrSetting)2012 MtrrGetAllMtrrs (
2013   OUT MTRR_SETTINGS                *MtrrSetting
2014   )
2015 {
2016   if (!IsMtrrSupported ()) {
2017     return MtrrSetting;
2018   }
2019 
2020   //
2021   // Get fixed MTRRs
2022   //
2023   MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);
2024 
2025   //
2026   // Get variable MTRRs
2027   //
2028   MtrrGetVariableMtrrWorker (
2029     NULL,
2030     GetVariableMtrrCountWorker (),
2031     &MtrrSetting->Variables
2032     );
2033 
2034   //
2035   // Get MTRR_DEF_TYPE value
2036   //
2037   MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
2038 
2039   return MtrrSetting;
2040 }
2041 
2042 
2043 /**
2044   This function sets all MTRRs (variable and fixed)
2045 
2046   @param[in]  MtrrSetting  A buffer holding all MTRRs content.
2047 
2048   @retval The pointer of MtrrSetting
2049 
2050 **/
2051 MTRR_SETTINGS *
2052 EFIAPI
MtrrSetAllMtrrs(IN MTRR_SETTINGS * MtrrSetting)2053 MtrrSetAllMtrrs (
2054   IN MTRR_SETTINGS                *MtrrSetting
2055   )
2056 {
2057   MTRR_CONTEXT  MtrrContext;
2058 
2059   if (!IsMtrrSupported ()) {
2060     return MtrrSetting;
2061   }
2062 
2063   PreMtrrChange (&MtrrContext);
2064 
2065   //
2066   // Set fixed MTRRs
2067   //
2068   MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
2069 
2070   //
2071   // Set variable MTRRs
2072   //
2073   MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
2074 
2075   //
2076   // Set MTRR_DEF_TYPE value
2077   //
2078   AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
2079 
2080   PostMtrrChangeEnableCache (&MtrrContext);
2081 
2082   MtrrDebugPrintAllMtrrs ();
2083 
2084   return MtrrSetting;
2085 }
2086 
2087 
2088 /**
2089   Checks if MTRR is supported.
2090 
2091   @retval TRUE  MTRR is supported.
2092   @retval FALSE MTRR is not supported.
2093 
2094 **/
2095 BOOLEAN
2096 EFIAPI
IsMtrrSupported(VOID)2097 IsMtrrSupported (
2098   VOID
2099   )
2100 {
2101   UINT32  RegEdx;
2102   UINT64  MtrrCap;
2103 
2104   //
2105   // Check CPUID(1).EDX[12] for MTRR capability
2106   //
2107   AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
2108   if (BitFieldRead32 (RegEdx, 12, 12) == 0) {
2109     return FALSE;
2110   }
2111 
2112   //
2113   // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
2114   // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
2115   // exist, return false.
2116   //
2117   MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);
2118   if  ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {
2119     return FALSE;
2120   }
2121 
2122   return TRUE;
2123 }
2124