1 /** @file
2 
3   Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
4   This program and the accompanying materials
5   are licensed and made available under the terms and conditions of the BSD License
6   which accompanies this distribution.  The full text of the license may be found at
7   http://opensource.org/licenses/bsd-license.php.
8 
9   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 **/
13 
14 #include <Uefi.h>
15 #include <Library/BaseLib.h>
16 #include <Library/CacheLib.h>
17 #include <Library/CacheAsRamLib.h>
18 #include "CacheLibInternal.h"
19 
20 /**
21   Search the memory cache type for specific memory from MTRR.
22 
23   @param[in]  MemoryAddress         the address of target memory
24   @param[in]  MemoryLength          the length of target memory
25   @param[in]  ValidMtrrAddressMask  the MTRR address mask
26   @param[out] UsedMsrNum            the used MSR number
27   @param[out] UsedMemoryCacheType   the cache type for the target memory
28 
29   @retval EFI_SUCCESS    The memory is found in MTRR and cache type is returned
30   @retval EFI_NOT_FOUND  The memory is not found in MTRR
31 
32 **/
33 EFI_STATUS
34 SearchForExactMtrr (
35   IN  EFI_PHYSICAL_ADDRESS      MemoryAddress,
36   IN  UINT64                    MemoryLength,
37   IN  UINT64                    ValidMtrrAddressMask,
38   OUT UINT32                    *UsedMsrNum,
39   OUT EFI_MEMORY_CACHE_TYPE     *MemoryCacheType
40   );
41 
42 /**
43   Check if CacheType match current default setting.
44 
45   @param[in] MemoryCacheType  input cache type to be checked.
46 
47   @retval TRUE MemoryCacheType is default MTRR setting.
48   @retval FALSE MemoryCacheType is NOT default MTRR setting.
49 **/
50 BOOLEAN
51 IsDefaultType (
52   IN  EFI_MEMORY_CACHE_TYPE     MemoryCacheType
53   );
54 
55 /**
56   Return MTRR alignment requirement for base address and size.
57 
58   @param[in]  BaseAddress     Base address.
59   @param[in]  Size            Size.
60 
61   @retval Zero      Alligned.
62   @retval Non-Zero  Not alligned.
63 
64 **/
65 UINT32
66 CheckMtrrAlignment (
67   IN  UINT64                    BaseAddress,
68   IN  UINT64                    Size
69   );
70 
71 typedef struct {
72   UINT32    Msr;
73   UINT32    BaseAddress;
74   UINT32    Length;
75 } EFI_FIXED_MTRR;
76 
77 EFI_FIXED_MTRR mFixedMtrrTable[] = {
78   { EFI_MSR_IA32_MTRR_FIX64K_00000, 0,       0x10000},
79   { EFI_MSR_IA32_MTRR_FIX16K_80000, 0x80000, 0x4000},
80   { EFI_MSR_IA32_MTRR_FIX16K_A0000, 0xA0000, 0x4000},
81   { EFI_MSR_IA32_MTRR_FIX4K_C0000,  0xC0000, 0x1000},
82   { EFI_MSR_IA32_MTRR_FIX4K_C8000,  0xC8000, 0x1000},
83   { EFI_MSR_IA32_MTRR_FIX4K_D0000,  0xD0000, 0x1000},
84   { EFI_MSR_IA32_MTRR_FIX4K_D8000,  0xD8000, 0x1000},
85   { EFI_MSR_IA32_MTRR_FIX4K_E0000,  0xE0000, 0x1000},
86   { EFI_MSR_IA32_MTRR_FIX4K_E8000,  0xE8000, 0x1000},
87   { EFI_MSR_IA32_MTRR_FIX4K_F0000,  0xF0000, 0x1000},
88   { EFI_MSR_IA32_MTRR_FIX4K_F8000,  0xF8000, 0x1000}
89 };
90 
91 /**
92   Given the input, check if the number of MTRR is lesser.
93   if positive or subtractive.
94 
95   @param[in]  Input   Length of Memory to program MTRR.
96 
97   @retval  Zero      do positive.
98   @retval  Non-Zero  do subtractive.
99 
100 **/
101 INT8
CheckDirection(IN UINT64 Input)102 CheckDirection (
103   IN  UINT64                    Input
104   )
105 {
106   return 0;
107 }
108 
109 /**
110   Disable cache and its mtrr.
111 
112   @param[out]  OldMtrr To return the Old MTRR value
113 
114 **/
115 VOID
EfiDisableCacheMtrr(OUT UINT64 * OldMtrr)116 EfiDisableCacheMtrr (
117   OUT UINT64                   *OldMtrr
118   )
119 {
120   UINT64  TempQword;
121 
122   //
123   // Disable Cache MTRR
124   //
125   *OldMtrr = AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE);
126   TempQword = (*OldMtrr) & ~B_EFI_MSR_GLOBAL_MTRR_ENABLE & ~B_EFI_MSR_FIXED_MTRR_ENABLE;
127   AsmWriteMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, TempQword);
128   AsmDisableCache ();
129 }
130 
131 /**
132   Recover cache MTRR.
133 
134   @param[in] EnableMtrr Whether to enable the MTRR
135   @param[in] OldMtrr    The saved old MTRR value to restore when not to enable the MTRR
136 
137 **/
138 VOID
EfiRecoverCacheMtrr(IN BOOLEAN EnableMtrr,IN UINT64 OldMtrr)139 EfiRecoverCacheMtrr (
140   IN BOOLEAN                  EnableMtrr,
141   IN UINT64                   OldMtrr
142   )
143 {
144   UINT64  TempQword;
145 
146   //
147   // Enable Cache MTRR
148   //
149   if (EnableMtrr) {
150     TempQword = AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE);
151     TempQword |= (UINT64)(B_EFI_MSR_GLOBAL_MTRR_ENABLE | B_EFI_MSR_FIXED_MTRR_ENABLE);
152   } else {
153     TempQword = OldMtrr;
154   }
155 
156   AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, TempQword);
157 
158   AsmEnableCache ();
159 }
160 
161 /**
162   Programming MTRR according to Memory address, length, and type.
163 
164   @param[in] MtrrNumber           the variable MTRR index number
165   @param[in] MemoryAddress        the address of target memory
166   @param[in] MemoryLength         the length of target memory
167   @param[in] MemoryCacheType      the cache type of target memory
168   @param[in] ValidMtrrAddressMask the MTRR address mask
169 
170 **/
171 VOID
EfiProgramMtrr(IN UINTN MtrrNumber,IN EFI_PHYSICAL_ADDRESS MemoryAddress,IN UINT64 MemoryLength,IN EFI_MEMORY_CACHE_TYPE MemoryCacheType,IN UINT64 ValidMtrrAddressMask)172 EfiProgramMtrr (
173   IN  UINTN                     MtrrNumber,
174   IN  EFI_PHYSICAL_ADDRESS      MemoryAddress,
175   IN  UINT64                    MemoryLength,
176   IN  EFI_MEMORY_CACHE_TYPE     MemoryCacheType,
177   IN  UINT64                    ValidMtrrAddressMask
178   )
179 {
180   UINT64                        TempQword;
181   UINT64                        OldMtrr;
182 
183   if (MemoryLength == 0) {
184     return;
185   }
186 
187   EfiDisableCacheMtrr (&OldMtrr);
188 
189   //
190   // MTRR Physical Base
191   //
192   TempQword = (MemoryAddress & ValidMtrrAddressMask) | MemoryCacheType;
193   AsmWriteMsr64 (MtrrNumber, TempQword);
194 
195   //
196   // MTRR Physical Mask
197   //
198   TempQword = ~(MemoryLength - 1);
199   AsmWriteMsr64 (MtrrNumber + 1, (TempQword & ValidMtrrAddressMask) | B_EFI_MSR_CACHE_MTRR_VALID);
200 
201   EfiRecoverCacheMtrr (TRUE, OldMtrr);
202 }
203 
204 /**
205   Calculate the maximum value which is a power of 2, but less the MemoryLength.
206 
207   @param[in]  MemoryAddress       Memory address.
208   @param[in]  MemoryLength        The number to pass in.
209 
210   @return The maximum value which is align to power of 2 and less the MemoryLength
211 
212 **/
213 UINT64
Power2MaxMemory(IN UINT64 MemoryAddress,IN UINT64 MemoryLength)214 Power2MaxMemory (
215   IN UINT64                 MemoryAddress,
216   IN UINT64                 MemoryLength
217   )
218 {
219   UINT64                    Result;
220 
221   if (MemoryLength == 0) {
222     return EFI_INVALID_PARAMETER;
223   }
224 
225   //
226   // Compute inital power of 2 size to return
227   //
228   Result = GetPowerOfTwo64(MemoryLength);
229 
230   //
231   // Special case base of 0 as all ranges are valid
232   //
233   if (MemoryAddress == 0) {
234     return Result;
235   }
236 
237   //
238   // Loop till a value that can be mapped to this base address is found
239   //
240   while (CheckMtrrAlignment (MemoryAddress, Result) != 0) {
241     //
242     // Need to try the next smaller power of 2
243     //
244     Result = RShiftU64 (Result, 1);
245   }
246 
247   return Result;
248 }
249 
250 /**
251   Return MTRR alignment requirement for base address and size.
252 
253   @param[in]  BaseAddress     Base address.
254   @param[in]  Size            Size.
255 
256   @retval Zero      Alligned.
257   @retval Non-Zero  Not alligned.
258 
259 **/
260 UINT32
CheckMtrrAlignment(IN UINT64 BaseAddress,IN UINT64 Size)261 CheckMtrrAlignment (
262   IN  UINT64    BaseAddress,
263   IN  UINT64    Size
264   )
265 {
266   UINT32      ShiftedBase;
267   UINT32      ShiftedSize;
268 
269   //
270   // Shift base and size right 12 bits to allow for larger memory sizes.  The
271   // MTRRs do not use the first 12 bits so this is safe for now.  Only supports
272   // up to 52 bits of physical address space.
273   //
274   ShiftedBase = (UINT32) RShiftU64 (BaseAddress, 12);
275   ShiftedSize = (UINT32) RShiftU64 (Size, 12);
276 
277   //
278   // Return the results to the caller of the MOD
279   //
280   return ShiftedBase % ShiftedSize;
281 }
282 
283 /**
284   Programs fixed MTRRs registers.
285 
286   @param[in]  MemoryCacheType  The memory type to set.
287   @param[in]  Base             The base address of memory range.
288   @param[in]  Length           The length of memory range.
289 
290   @retval RETURN_SUCCESS      The cache type was updated successfully
291   @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid
292                               for the fixed MTRRs.
293 
294 **/
295 EFI_STATUS
ProgramFixedMtrr(IN EFI_MEMORY_CACHE_TYPE MemoryCacheType,IN UINT64 * Base,IN UINT64 * Len)296 ProgramFixedMtrr (
297   IN  EFI_MEMORY_CACHE_TYPE     MemoryCacheType,
298   IN  UINT64                    *Base,
299   IN  UINT64                    *Len
300   )
301 {
302   UINT32                      MsrNum;
303   UINT32                      ByteShift;
304   UINT64                      TempQword;
305   UINT64                      OrMask;
306   UINT64                      ClearMask;
307 
308   TempQword = 0;
309   OrMask =  0;
310   ClearMask = 0;
311 
312   for (MsrNum = 0; MsrNum < V_EFI_FIXED_MTRR_NUMBER; MsrNum++) {
313     if ((*Base >= mFixedMtrrTable[MsrNum].BaseAddress) &&
314         (*Base < (mFixedMtrrTable[MsrNum].BaseAddress + 8 * mFixedMtrrTable[MsrNum].Length))) {
315       break;
316     }
317   }
318   if (MsrNum == V_EFI_FIXED_MTRR_NUMBER ) {
319     return EFI_DEVICE_ERROR;
320   }
321   //
322   // We found the fixed MTRR to be programmed
323   //
324   for (ByteShift=0; ByteShift < 8; ByteShift++) {
325     if ( *Base == (mFixedMtrrTable[MsrNum].BaseAddress + ByteShift * mFixedMtrrTable[MsrNum].Length)) {
326       break;
327     }
328   }
329   if (ByteShift == 8 ) {
330     return EFI_DEVICE_ERROR;
331   }
332   for (; ((ByteShift<8) && (*Len >= mFixedMtrrTable[MsrNum].Length));ByteShift++) {
333     OrMask |= LShiftU64((UINT64) MemoryCacheType, (UINT32) (ByteShift* 8));
334     ClearMask |= LShiftU64((UINT64) 0xFF, (UINT32) (ByteShift * 8));
335     *Len -= mFixedMtrrTable[MsrNum].Length;
336     *Base += mFixedMtrrTable[MsrNum].Length;
337   }
338   TempQword = (AsmReadMsr64 (mFixedMtrrTable[MsrNum].Msr) & (~ClearMask)) | OrMask;
339   AsmWriteMsr64 (mFixedMtrrTable[MsrNum].Msr, TempQword);
340 
341   return EFI_SUCCESS;
342 }
343 
344 /**
345   Check if there is a valid variable MTRR that overlaps the given range.
346 
347   @param[in]  Start  Base Address of the range to check.
348   @param[in]  End    End address of the range to check.
349 
350   @retval TRUE   Mtrr overlap.
351   @retval FALSE  Mtrr not overlap.
352 **/
353 BOOLEAN
CheckMtrrOverlap(IN EFI_PHYSICAL_ADDRESS Start,IN EFI_PHYSICAL_ADDRESS End)354 CheckMtrrOverlap (
355   IN  EFI_PHYSICAL_ADDRESS      Start,
356   IN  EFI_PHYSICAL_ADDRESS      End
357   )
358 {
359   return FALSE;
360 }
361 
362 /**
363   Given the memory range and cache type, programs the MTRRs.
364 
365   @param[in] MemoryAddress           Base Address of Memory to program MTRR.
366   @param[in] MemoryLength            Length of Memory to program MTRR.
367   @param[in] MemoryCacheType         Cache Type.
368 
369   @retval EFI_SUCCESS            Mtrr are set successfully.
370   @retval EFI_LOAD_ERROR         No empty MTRRs to use.
371   @retval EFI_INVALID_PARAMETER  The input parameter is not valid.
372   @retval others                 An error occurs when setting MTTR.
373 
374 **/
375 EFI_STATUS
376 EFIAPI
SetCacheAttributes(IN EFI_PHYSICAL_ADDRESS MemoryAddress,IN UINT64 MemoryLength,IN EFI_MEMORY_CACHE_TYPE MemoryCacheType)377 SetCacheAttributes (
378   IN  EFI_PHYSICAL_ADDRESS      MemoryAddress,
379   IN  UINT64                    MemoryLength,
380   IN  EFI_MEMORY_CACHE_TYPE     MemoryCacheType
381   )
382 {
383   EFI_STATUS            Status;
384   UINT32                MsrNum, MsrNumEnd;
385   UINT64                TempQword;
386   UINT32                LastVariableMtrrForBios;
387   UINT64                OldMtrr;
388   UINT32                UsedMsrNum;
389   EFI_MEMORY_CACHE_TYPE UsedMemoryCacheType;
390   UINT64                ValidMtrrAddressMask;
391   UINT32                Cpuid_RegEax;
392 
393   AsmCpuid (CPUID_EXTENDED_FUNCTION, &Cpuid_RegEax, NULL, NULL, NULL);
394   if (Cpuid_RegEax >= CPUID_VIR_PHY_ADDRESS_SIZE) {
395     AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &Cpuid_RegEax, NULL, NULL, NULL);
396     ValidMtrrAddressMask = (LShiftU64((UINT64) 1, (Cpuid_RegEax & 0xFF)) - 1) & (~(UINT64)0x0FFF);
397   } else {
398     ValidMtrrAddressMask = (LShiftU64((UINT64) 1, 36) - 1) & (~(UINT64)0x0FFF);
399   }
400 
401   //
402   // Check for invalid parameter
403   //
404   if ((MemoryAddress & ~ValidMtrrAddressMask) != 0 || (MemoryLength & ~ValidMtrrAddressMask) != 0) {
405     return EFI_INVALID_PARAMETER;
406   }
407 
408   if (MemoryLength == 0) {
409     return EFI_INVALID_PARAMETER;
410   }
411 
412   switch (MemoryCacheType) {
413     case EFI_CACHE_UNCACHEABLE:
414     case EFI_CACHE_WRITECOMBINING:
415     case EFI_CACHE_WRITETHROUGH:
416     case EFI_CACHE_WRITEPROTECTED:
417     case EFI_CACHE_WRITEBACK:
418       break;
419 
420     default:
421       return EFI_INVALID_PARAMETER;
422   }
423 
424   //
425   // Check if Fixed MTRR
426   //
427   if ((MemoryAddress + MemoryLength) <= (1 << 20)) {
428     Status = EFI_SUCCESS;
429     EfiDisableCacheMtrr (&OldMtrr);
430     while ((MemoryLength > 0) && (Status == EFI_SUCCESS)) {
431       Status = ProgramFixedMtrr (MemoryCacheType, &MemoryAddress, &MemoryLength);
432     }
433     EfiRecoverCacheMtrr (TRUE, OldMtrr);
434     return Status;
435   }
436 
437   //
438   // Search if the range attribute has been set before
439   //
440   Status = SearchForExactMtrr(
441                               MemoryAddress,
442                               MemoryLength,
443                               ValidMtrrAddressMask,
444                               &UsedMsrNum,
445                               &UsedMemoryCacheType
446                               );
447 
448   if (!EFI_ERROR(Status)) {
449     //
450     // Compare if it has the same type as current setting
451     //
452     if (UsedMemoryCacheType == MemoryCacheType) {
453       return EFI_SUCCESS;
454     } else {
455       //
456       // Different type
457       //
458 
459       //
460       // Check if the set type is the same as Default Type
461       //
462       if (IsDefaultType(MemoryCacheType)) {
463         //
464         // Clear the MTRR
465         //
466         AsmWriteMsr64(UsedMsrNum, 0);
467         AsmWriteMsr64(UsedMsrNum + 1, 0);
468 
469         return EFI_SUCCESS;
470       } else {
471         //
472         // Modify the MTRR type
473         //
474         EfiProgramMtrr(UsedMsrNum,
475                        MemoryAddress,
476                        MemoryLength,
477                        MemoryCacheType,
478                        ValidMtrrAddressMask
479                        );
480         return EFI_SUCCESS;
481       }
482     }
483   }
484 
485 #if 0
486   //
487   // @bug - Need to create memory map so that when checking for overlap we
488   //        can determine if an overlap exists based on all caching requests.
489   //
490   // Don't waste a variable MTRR if the caching attrib is same as default in MTRR_DEF_TYPE
491   //
492   if (MemoryCacheType == (AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE) & B_EFI_MSR_CACHE_MEMORY_TYPE))  {
493     if (!CheckMtrrOverlap (MemoryAddress, MemoryAddress+MemoryLength-1)) {
494       return EFI_SUCCESS;
495     }
496   }
497 #endif
498 
499   //
500   // Find first unused MTRR
501   //
502   MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));
503   for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum +=2) {
504     if ((AsmReadMsr64(MsrNum+1) & B_EFI_MSR_CACHE_MTRR_VALID) == 0 ) {
505       break;
506     }
507   }
508 
509   //
510   // Reserve 1 MTRR pair for OS.
511   //
512   LastVariableMtrrForBios = MsrNumEnd - 1 - (EFI_CACHE_NUM_VAR_MTRR_PAIRS_FOR_OS * 2);
513   if (MsrNum > LastVariableMtrrForBios) {
514     return EFI_LOAD_ERROR;
515   }
516 
517   //
518   // Special case for 1 MB base address
519   //
520   if (MemoryAddress == BASE_1MB) {
521     MemoryAddress = 0;
522   }
523 
524   //
525   // Program MTRRs
526   //
527   TempQword = MemoryLength;
528 
529   if (TempQword == Power2MaxMemory(MemoryAddress, TempQword)) {
530     EfiProgramMtrr(MsrNum,
531                    MemoryAddress,
532                    MemoryLength,
533                    MemoryCacheType,
534                    ValidMtrrAddressMask
535                    );
536 
537   } else {
538     //
539     // Fill in MTRRs with values.  Direction can not be checked for this method
540     // as we are using WB as the default cache type and only setting areas to UC.
541     //
542     do {
543       //
544       // Do boundary check so we don't go past last MTRR register
545       // for BIOS use.  Leave one MTRR pair for OS use.
546       //
547       if (MsrNum > LastVariableMtrrForBios) {
548         return EFI_LOAD_ERROR;
549       }
550 
551       //
552       // Set next power of 2 region
553       //
554       MemoryLength = Power2MaxMemory(MemoryAddress, TempQword);
555       EfiProgramMtrr(MsrNum,
556                      MemoryAddress,
557                      MemoryLength,
558                      MemoryCacheType,
559                      ValidMtrrAddressMask
560                      );
561       MemoryAddress += MemoryLength;
562       TempQword -= MemoryLength;
563       MsrNum += 2;
564     } while (TempQword != 0);
565   }
566 
567   return EFI_SUCCESS;
568 }
569 
570 /**
571  Reset all the MTRRs to a known state.
572 
573   @retval  EFI_SUCCESS All MTRRs have been reset successfully.
574 
575 **/
576 EFI_STATUS
577 EFIAPI
ResetCacheAttributes(VOID)578 ResetCacheAttributes (
579   VOID
580   )
581 {
582   UINT32                      MsrNum, MsrNumEnd;
583   UINT16                      Index;
584   UINT64                      OldMtrr;
585   UINT64                      CacheType;
586   BOOLEAN                     DisableCar;
587   Index = 0;
588   DisableCar = TRUE;
589 
590   //
591   // Determine default cache type
592   //
593   CacheType = EFI_CACHE_UNCACHEABLE;
594 
595   //
596   // Set default cache type
597   //
598   AsmWriteMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, CacheType);
599 
600   //
601   // Disable CAR
602   //
603   DisableCacheAsRam (DisableCar);
604 
605   EfiDisableCacheMtrr (&OldMtrr);
606 
607   //
608   // Reset Fixed MTRRs
609   //
610   for (Index = 0; Index < V_EFI_FIXED_MTRR_NUMBER; Index++) {
611     AsmWriteMsr64 (mFixedMtrrTable[Index].Msr, 0);
612   }
613 
614   //
615   // Reset Variable MTRRs
616   //
617   MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));
618   for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum++) {
619     AsmWriteMsr64 (MsrNum, 0);
620   }
621 
622   //
623   // Enable Fixed and Variable MTRRs
624   //
625   EfiRecoverCacheMtrr (TRUE, OldMtrr);
626 
627   return EFI_SUCCESS;
628 }
629 
630 /**
631   Search the memory cache type for specific memory from MTRR.
632 
633   @param[in]  MemoryAddress         the address of target memory
634   @param[in]  MemoryLength          the length of target memory
635   @param[in]  ValidMtrrAddressMask  the MTRR address mask
636   @param[out] UsedMsrNum            the used MSR number
637   @param[out] UsedMemoryCacheType   the cache type for the target memory
638 
639   @retval EFI_SUCCESS    The memory is found in MTRR and cache type is returned
640   @retval EFI_NOT_FOUND  The memory is not found in MTRR
641 
642 **/
643 EFI_STATUS
SearchForExactMtrr(IN EFI_PHYSICAL_ADDRESS MemoryAddress,IN UINT64 MemoryLength,IN UINT64 ValidMtrrAddressMask,OUT UINT32 * UsedMsrNum,OUT EFI_MEMORY_CACHE_TYPE * UsedMemoryCacheType)644 SearchForExactMtrr (
645   IN  EFI_PHYSICAL_ADDRESS      MemoryAddress,
646   IN  UINT64                    MemoryLength,
647   IN  UINT64                    ValidMtrrAddressMask,
648   OUT UINT32                    *UsedMsrNum,
649   OUT EFI_MEMORY_CACHE_TYPE     *UsedMemoryCacheType
650   )
651 {
652   UINT32                      MsrNum, MsrNumEnd;
653   UINT64                      TempQword;
654 
655   if (MemoryLength == 0) {
656     return EFI_INVALID_PARAMETER;
657   }
658 
659   MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));
660   for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum +=2) {
661     TempQword = AsmReadMsr64(MsrNum+1);
662     if ((TempQword & B_EFI_MSR_CACHE_MTRR_VALID) == 0) {
663       continue;
664     }
665 
666     if ((TempQword & ValidMtrrAddressMask) != ((~(MemoryLength - 1)) & ValidMtrrAddressMask)) {
667       continue;
668     }
669 
670     TempQword = AsmReadMsr64 (MsrNum);
671     if ((TempQword & ValidMtrrAddressMask) != (MemoryAddress & ValidMtrrAddressMask)) {
672       continue;
673     }
674 
675     *UsedMemoryCacheType = (EFI_MEMORY_CACHE_TYPE)(TempQword & B_EFI_MSR_CACHE_MEMORY_TYPE);
676     *UsedMsrNum = MsrNum;
677 
678     return EFI_SUCCESS;
679   }
680 
681   return EFI_NOT_FOUND;
682 }
683 
684 /**
685   Check if CacheType match current default setting.
686 
687   @param[in] MemoryCacheType  input cache type to be checked.
688 
689   @retval TRUE MemoryCacheType is default MTRR setting.
690   @retval TRUE MemoryCacheType is NOT default MTRR setting.
691 **/
692 BOOLEAN
IsDefaultType(IN EFI_MEMORY_CACHE_TYPE MemoryCacheType)693 IsDefaultType (
694   IN  EFI_MEMORY_CACHE_TYPE     MemoryCacheType
695   )
696 {
697   if ((AsmReadMsr64(EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE) & B_EFI_MSR_CACHE_MEMORY_TYPE) != MemoryCacheType) {
698     return FALSE;
699   }
700 
701   return TRUE;
702 }
703 
704