MtrrLib.c revision ed8dfd7bfeec6fe5333d6a90706d72af5ddee03d
1/** @file
2  MTRR setting library
3
4  Copyright (c) 2008 - 2010, Intel Corporation
5  All rights reserved. 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// This table defines the offset, base and length of the fixed MTRRs
25//
26STATIC
27FIXED_MTRR    MtrrLibFixedMtrrTable[] = {
28  {
29    MTRR_LIB_IA32_MTRR_FIX64K_00000,
30    0,
31    SIZE_64KB
32  },
33  {
34    MTRR_LIB_IA32_MTRR_FIX16K_80000,
35    0x80000,
36    SIZE_16KB
37  },
38  {
39    MTRR_LIB_IA32_MTRR_FIX16K_A0000,
40    0xA0000,
41    SIZE_16KB
42  },
43  {
44    MTRR_LIB_IA32_MTRR_FIX4K_C0000,
45    0xC0000,
46    SIZE_4KB
47  },
48  {
49    MTRR_LIB_IA32_MTRR_FIX4K_C8000,
50    0xC8000,
51    SIZE_4KB
52  },
53  {
54    MTRR_LIB_IA32_MTRR_FIX4K_D0000,
55    0xD0000,
56    SIZE_4KB
57  },
58  {
59    MTRR_LIB_IA32_MTRR_FIX4K_D8000,
60    0xD8000,
61    SIZE_4KB
62  },
63  {
64    MTRR_LIB_IA32_MTRR_FIX4K_E0000,
65    0xE0000,
66    SIZE_4KB
67  },
68  {
69    MTRR_LIB_IA32_MTRR_FIX4K_E8000,
70    0xE8000,
71    SIZE_4KB
72  },
73  {
74    MTRR_LIB_IA32_MTRR_FIX4K_F0000,
75    0xF0000,
76    SIZE_4KB
77  },
78  {
79    MTRR_LIB_IA32_MTRR_FIX4K_F8000,
80    0xF8000,
81    SIZE_4KB
82  },
83};
84
85/**
86  Returns the variable MTRR count for the CPU.
87
88  @return Variable MTRR count
89
90**/
91UINT32
92EFIAPI
93GetVariableMtrrCount (
94  VOID
95  )
96{
97  if (!IsMtrrSupported ()) {
98    return 0;
99  }
100
101  return (UINT32)(AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);
102}
103
104/**
105  Returns the firmware usable variable MTRR count for the CPU.
106
107  @return Firmware usable variable MTRR count
108
109**/
110UINT32
111EFIAPI
112GetFirmwareVariableMtrrCount (
113  VOID
114  )
115{
116  UINT32  VariableMtrrCount;
117
118  VariableMtrrCount = GetVariableMtrrCount ();
119  if (VariableMtrrCount < RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER) {
120    return 0;
121  }
122
123  return VariableMtrrCount - RESERVED_FIRMWARE_VARIABLE_MTRR_NUMBER;
124}
125
126/**
127  Returns the default MTRR cache type for the system.
128
129  @return  MTRR default type
130
131**/
132UINT64
133GetMtrrDefaultMemoryType (
134  VOID
135)
136{
137  return (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0xff);
138}
139
140
141/**
142  Preparation before programming MTRR.
143
144  This function will do some preparation for programming MTRRs:
145  disable cache, invalid cache and disable MTRR caching functionality
146
147  @return  CR4 value before changing.
148
149**/
150UINTN
151PreMtrrChange (
152  VOID
153  )
154{
155  UINTN  Value;
156
157  //
158  // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
159  //
160  AsmDisableCache ();
161
162  //
163  // Save original CR4 value and clear PGE flag (Bit 7)
164  //
165  Value = AsmReadCr4 ();
166  AsmWriteCr4 (Value & (~BIT7));
167
168  //
169  // Flush all TLBs
170  //
171  CpuFlushTlb ();
172
173  //
174  // Disable Mtrrs
175  //
176  AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);
177
178  //
179  // Return original CR4 value
180  //
181  return Value;
182}
183
184
185/**
186  Cleaning up after programming MTRRs.
187
188  This function will do some clean up after programming MTRRs:
189  enable MTRR caching functionality, and enable cache
190
191  @param  Cr4  CR4 value to restore
192
193**/
194VOID
195PostMtrrChange (
196  UINTN Cr4
197  )
198{
199  //
200  // Enable Cache MTRR
201  //
202  AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);
203
204  //
205  // Flush all TLBs
206  //
207  CpuFlushTlb ();
208
209  //
210  // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
211  //
212  AsmEnableCache ();
213
214  //
215  // Restore original CR4 value
216  //
217  AsmWriteCr4 (Cr4);
218}
219
220
221/**
222  Programs fixed MTRRs registers.
223
224  @param  MemoryCacheType  The memory type to set.
225  @param  Base             The base address of memory range.
226  @param  Length           The length of memory range.
227
228  @retval RETURN_SUCCESS      The cache type was updated successfully
229  @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid
230                              for the fixed MTRRs.
231
232**/
233RETURN_STATUS
234ProgramFixedMtrr (
235  IN     UINT64     MemoryCacheType,
236  IN OUT UINT64     *Base,
237  IN OUT UINT64     *Length
238  )
239{
240  UINT32  MsrNum;
241  UINT32  ByteShift;
242  UINT64  TempQword;
243  UINT64  OrMask;
244  UINT64  ClearMask;
245
246  TempQword = 0;
247  OrMask    = 0;
248  ClearMask = 0;
249
250  for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {
251    if ((*Base >= MtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&
252        (*Base <
253            (
254              MtrrLibFixedMtrrTable[MsrNum].BaseAddress +
255              (8 * MtrrLibFixedMtrrTable[MsrNum].Length)
256            )
257          )
258        ) {
259      break;
260    }
261  }
262
263  if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {
264    return RETURN_UNSUPPORTED;
265  }
266
267  //
268  // We found the fixed MTRR to be programmed
269  //
270  for (ByteShift = 0; ByteShift < 8; ByteShift++) {
271    if (*Base ==
272         (
273           MtrrLibFixedMtrrTable[MsrNum].BaseAddress +
274           (ByteShift * MtrrLibFixedMtrrTable[MsrNum].Length)
275         )
276       ) {
277      break;
278    }
279  }
280
281  if (ByteShift == 8) {
282    return RETURN_UNSUPPORTED;
283  }
284
285  for (
286        ;
287        ((ByteShift < 8) && (*Length >= MtrrLibFixedMtrrTable[MsrNum].Length));
288        ByteShift++
289      ) {
290    OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));
291    ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));
292    *Length -= MtrrLibFixedMtrrTable[MsrNum].Length;
293    *Base += MtrrLibFixedMtrrTable[MsrNum].Length;
294  }
295
296  if (ByteShift < 8 && (*Length != 0)) {
297    return RETURN_UNSUPPORTED;
298  }
299
300  TempQword =
301    (AsmReadMsr64 (MtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;
302  AsmWriteMsr64 (MtrrLibFixedMtrrTable[MsrNum].Msr, TempQword);
303  return RETURN_SUCCESS;
304}
305
306
307/**
308  Get the attribute of variable MTRRs.
309
310  This function shadows the content of variable MTRRs into an
311  internal array: VariableMtrr.
312
313  @param  MtrrValidBitsMask     The mask for the valid bit of the MTRR
314  @param  MtrrValidAddressMask  The valid address mask for MTRR
315  @param  VariableMtrr          The array to shadow variable MTRRs content
316
317  @return                       The return value of this paramter indicates the
318                                number of MTRRs which has been used.
319
320**/
321UINT32
322EFIAPI
323MtrrGetMemoryAttributeInVariableMtrr (
324  IN  UINT64                    MtrrValidBitsMask,
325  IN  UINT64                    MtrrValidAddressMask,
326  OUT VARIABLE_MTRR             *VariableMtrr
327  )
328{
329  UINTN   Index;
330  UINT32  MsrNum;
331  UINT32  UsedMtrr;
332  UINT32  FirmwareVariableMtrrCount;
333  UINT32  VariableMtrrEnd;
334
335  if (!IsMtrrSupported ()) {
336    return 0;
337  }
338
339  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
340  VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;
341
342  ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);
343  UsedMtrr = 0;
344
345  for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE, Index = 0;
346       (
347         (MsrNum < VariableMtrrEnd) &&
348         (Index < FirmwareVariableMtrrCount)
349       );
350       MsrNum += 2
351      ) {
352    if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {
353      VariableMtrr[Index].Msr          = MsrNum;
354      VariableMtrr[Index].BaseAddress  = (AsmReadMsr64 (MsrNum) &
355                                          MtrrValidAddressMask);
356      VariableMtrr[Index].Length       = ((~(AsmReadMsr64 (MsrNum + 1) &
357                                             MtrrValidAddressMask)
358                                          ) &
359                                          MtrrValidBitsMask
360                                         ) + 1;
361      VariableMtrr[Index].Type         = (AsmReadMsr64 (MsrNum) & 0x0ff);
362      VariableMtrr[Index].Valid        = TRUE;
363      VariableMtrr[Index].Used         = TRUE;
364      UsedMtrr = UsedMtrr  + 1;
365      Index++;
366    }
367  }
368  return UsedMtrr;
369}
370
371
372/**
373  Checks overlap between given memory range and MTRRs.
374
375  @param  Start            The start address of memory range.
376  @param  End              The end address of memory range.
377  @param  VariableMtrr     The array to shadow variable MTRRs content
378
379  @retval TRUE             Overlap exists.
380  @retval FALSE            No overlap.
381
382**/
383BOOLEAN
384CheckMemoryAttributeOverlap (
385  IN PHYSICAL_ADDRESS     Start,
386  IN PHYSICAL_ADDRESS     End,
387  IN VARIABLE_MTRR      *VariableMtrr
388  )
389{
390  UINT32  Index;
391
392  for (Index = 0; Index < 6; Index++) {
393    if (
394         VariableMtrr[Index].Valid &&
395         !(
396           (Start > (VariableMtrr[Index].BaseAddress +
397                     VariableMtrr[Index].Length - 1)
398           ) ||
399           (End < VariableMtrr[Index].BaseAddress)
400         )
401       ) {
402      return TRUE;
403    }
404  }
405
406  return FALSE;
407}
408
409
410/**
411  Marks a variable MTRR as non-valid.
412
413  @param  Index         The index of the array VariableMtrr to be invalidated
414  @param  VariableMtrr  The array to shadow variable MTRRs content
415  @param  UsedMtrr      The number of MTRRs which has already been used
416
417**/
418VOID
419InvalidateShadowMtrr (
420  IN   UINTN              Index,
421  IN   VARIABLE_MTRR      *VariableMtrr,
422  OUT  UINT32             *UsedMtrr
423  )
424{
425  VariableMtrr[Index].Valid = FALSE;
426  *UsedMtrr = *UsedMtrr - 1;
427}
428
429
430/**
431  Combine memory attributes.
432
433  If overlap exists between given memory range and MTRRs, try to combine them.
434
435  @param  Attributes             The memory type to set.
436  @param  Base                   The base address of memory range.
437  @param  Length                 The length of memory range.
438  @param  VariableMtrr           The array to shadow variable MTRRs content
439  @param  UsedMtrr               The number of MTRRs which has already been used
440  @param  OverwriteExistingMtrr  Returns whether an existing MTRR was used
441
442  @retval EFI_SUCCESS            Memory region successfully combined.
443  @retval EFI_ACCESS_DENIED      Memory region cannot be combined.
444
445**/
446RETURN_STATUS
447CombineMemoryAttribute (
448  IN     UINT64             Attributes,
449  IN OUT UINT64             *Base,
450  IN OUT UINT64             *Length,
451  IN     VARIABLE_MTRR      *VariableMtrr,
452  IN OUT UINT32             *UsedMtrr,
453  OUT    BOOLEAN            *OverwriteExistingMtrr
454  )
455{
456  UINT32  Index;
457  UINT64  CombineStart;
458  UINT64  CombineEnd;
459  UINT64  MtrrEnd;
460  UINT64  EndAddress;
461  UINT32  FirmwareVariableMtrrCount;
462
463  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
464
465  *OverwriteExistingMtrr = FALSE;
466  EndAddress = *Base +*Length - 1;
467
468  for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
469
470    MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;
471    if (
472         !VariableMtrr[Index].Valid ||
473         (
474           *Base > (MtrrEnd) ||
475           (EndAddress < VariableMtrr[Index].BaseAddress)
476         )
477       ) {
478      continue;
479    }
480
481    //
482    // Combine same attribute MTRR range
483    //
484    if (Attributes == VariableMtrr[Index].Type) {
485      //
486      // if the Mtrr range contain the request range, return RETURN_SUCCESS
487      //
488      if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {
489        *Length = 0;
490        return RETURN_SUCCESS;
491      }
492      //
493      // invalid this MTRR, and program the combine range
494      //
495      CombineStart  =
496        (*Base) < VariableMtrr[Index].BaseAddress ?
497          (*Base) :
498          VariableMtrr[Index].BaseAddress;
499      CombineEnd    = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;
500
501      //
502      // Record the MTRR usage status in VariableMtrr array.
503      //
504      InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
505      *Base       = CombineStart;
506      *Length     = CombineEnd - CombineStart + 1;
507      EndAddress  = CombineEnd;
508      *OverwriteExistingMtrr = TRUE;
509      continue;
510    } else {
511      //
512      // The cache type is different, but the range is convered by one MTRR
513      //
514      if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {
515        InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);
516        continue;
517      }
518
519    }
520
521    if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&
522         VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||
523        (Attributes == MTRR_CACHE_WRITE_BACK &&
524         VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||
525        (Attributes == MTRR_CACHE_UNCACHEABLE) ||
526        (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)
527     ) {
528      *OverwriteExistingMtrr = TRUE;
529      continue;
530    }
531    //
532    // Other type memory overlap is invalid
533    //
534    return RETURN_ACCESS_DENIED;
535  }
536
537  return RETURN_SUCCESS;
538}
539
540
541/**
542  Calculate the maximum value which is a power of 2, but less the MemoryLength.
543
544  @param  MemoryLength        The number to pass in.
545  @return The maximum value which is align to power of 2 and less the MemoryLength
546
547**/
548UINT64
549Power2MaxMemory (
550  IN UINT64                     MemoryLength
551  )
552{
553  UINT64  Result;
554
555  if (RShiftU64 (MemoryLength, 32)) {
556    Result = LShiftU64 (
557               (UINT64) GetPowerOfTwo32 (
558                          (UINT32) RShiftU64 (MemoryLength, 32)
559                          ),
560               32
561               );
562  } else {
563    Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);
564  }
565
566  return Result;
567}
568
569
570/**
571  Check the direction to program variable MTRRs.
572
573  This function determines which direction of programming the variable
574  MTRRs will use fewer MTRRs.
575
576  @param  Input       Length of Memory to program MTRR
577  @param  MtrrNumber  Pointer to the number of necessary MTRRs
578
579  @retval TRUE        Positive direction is better.
580          FALSE       Negtive direction is better.
581
582**/
583BOOLEAN
584GetDirection (
585  IN UINT64      Input,
586  IN UINTN       *MtrrNumber
587  )
588{
589  UINT64  TempQword;
590  UINT32  Positive;
591  UINT32  Subtractive;
592
593  TempQword   = Input;
594  Positive    = 0;
595  Subtractive = 0;
596
597  do {
598    TempQword -= Power2MaxMemory (TempQword);
599    Positive++;
600  } while (TempQword != 0);
601
602  TempQword = Power2MaxMemory (LShiftU64 (Input, 1)) - Input;
603  Subtractive++;
604  do {
605    TempQword -= Power2MaxMemory (TempQword);
606    Subtractive++;
607  } while (TempQword != 0);
608
609  if (Positive <= Subtractive) {
610    *MtrrNumber = Positive;
611    return TRUE;
612  } else {
613    *MtrrNumber = Subtractive;
614    return FALSE;
615  }
616}
617
618/**
619  Invalid variable MTRRs according to the value in the shadow array.
620
621  This function programs MTRRs according to the values specified
622  in the shadow array.
623
624  @param  VariableMtrr   The array to shadow variable MTRRs content
625
626**/
627STATIC
628VOID
629InvalidateMtrr (
630   IN     VARIABLE_MTRR      *VariableMtrr
631   )
632{
633  UINTN Index;
634  UINTN Cr4;
635  UINTN VariableMtrrCount;
636
637  Cr4 = PreMtrrChange ();
638  Index = 0;
639  VariableMtrrCount = GetVariableMtrrCount ();
640  while (Index < VariableMtrrCount) {
641    if (VariableMtrr[Index].Valid == FALSE && VariableMtrr[Index].Used == TRUE ) {
642       AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);
643       AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);
644       VariableMtrr[Index].Used = FALSE;
645    }
646    Index ++;
647  }
648  PostMtrrChange (Cr4);
649}
650
651
652/**
653  Programs variable MTRRs
654
655  This function programs variable MTRRs
656
657  @param  MtrrNumber            Index of MTRR to program.
658  @param  BaseAddress           Base address of memory region.
659  @param  Length                Length of memory region.
660  @param  MemoryCacheType       Memory type to set.
661  @param  MtrrValidAddressMask  The valid address mask for MTRR
662
663**/
664STATIC
665VOID
666ProgramVariableMtrr (
667  IN UINTN                    MtrrNumber,
668  IN PHYSICAL_ADDRESS         BaseAddress,
669  IN UINT64                   Length,
670  IN UINT64                   MemoryCacheType,
671  IN UINT64                   MtrrValidAddressMask
672  )
673{
674  UINT64  TempQword;
675  UINTN   Cr4;
676
677  Cr4 = PreMtrrChange ();
678
679  //
680  // MTRR Physical Base
681  //
682  TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;
683  AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);
684
685  //
686  // MTRR Physical Mask
687  //
688  TempQword = ~(Length - 1);
689  AsmWriteMsr64 (
690    (UINT32) (MtrrNumber + 1),
691    (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED
692    );
693
694  PostMtrrChange (Cr4);
695}
696
697
698/**
699  Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.
700
701  @param  MtrrType  MTRR memory type
702
703  @return The enum item in MTRR_MEMORY_CACHE_TYPE
704
705**/
706STATIC
707MTRR_MEMORY_CACHE_TYPE
708GetMemoryCacheTypeFromMtrrType (
709  IN UINT64                MtrrType
710  )
711{
712  switch (MtrrType) {
713  case MTRR_CACHE_UNCACHEABLE:
714    return CacheUncacheable;
715  case MTRR_CACHE_WRITE_COMBINING:
716    return CacheWriteCombining;
717  case MTRR_CACHE_WRITE_THROUGH:
718    return CacheWriteThrough;
719  case MTRR_CACHE_WRITE_PROTECTED:
720    return CacheWriteProtected;
721  case MTRR_CACHE_WRITE_BACK:
722    return CacheWriteBack;
723  default:
724    //
725    // MtrrType is MTRR_CACHE_INVALID_TYPE, that means
726    // no mtrr covers the range
727    //
728    return CacheUncacheable;
729  }
730}
731
732/**
733  Initializes the valid bits mask and valid address mask for MTRRs.
734
735  This function initializes the valid bits mask and valid address mask for MTRRs.
736
737  @param  MtrrValidBitsMask     The mask for the valid bit of the MTRR
738  @param  MtrrValidAddressMask  The valid address mask for the MTRR
739
740**/
741STATIC
742VOID
743MtrrLibInitializeMtrrMask (
744  OUT UINT64 *MtrrValidBitsMask,
745  OUT UINT64 *MtrrValidAddressMask
746  )
747{
748  UINT32                              RegEax;
749  UINT8                               PhysicalAddressBits;
750
751  AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
752
753  if (RegEax >= 0x80000008) {
754    AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
755
756    PhysicalAddressBits = (UINT8) RegEax;
757
758    *MtrrValidBitsMask    = LShiftU64 (1, PhysicalAddressBits) - 1;
759    *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
760  } else {
761    *MtrrValidBitsMask    = MTRR_LIB_CACHE_VALID_ADDRESS;
762    *MtrrValidAddressMask = 0xFFFFFFFF;
763  }
764}
765
766
767/**
768  Determing the real attribute of a memory range.
769
770  This function is to arbitrate the real attribute of the memory when
771  there are 2 MTRR covers the same memory range.  For further details,
772  please refer the IA32 Software Developer's Manual, Volume 3,
773  Section 10.11.4.1.
774
775  @param  MtrrType1    the first kind of Memory type
776  @param  MtrrType2    the second kind of memory type
777
778**/
779UINT64
780MtrrPrecedence (
781  UINT64    MtrrType1,
782  UINT64    MtrrType2
783  )
784{
785  UINT64 MtrrType;
786
787  MtrrType = MTRR_CACHE_INVALID_TYPE;
788  switch (MtrrType1) {
789  case MTRR_CACHE_UNCACHEABLE:
790    MtrrType = MTRR_CACHE_UNCACHEABLE;
791    break;
792  case MTRR_CACHE_WRITE_COMBINING:
793    if (
794         MtrrType2==MTRR_CACHE_WRITE_COMBINING ||
795         MtrrType2==MTRR_CACHE_UNCACHEABLE
796       ) {
797      MtrrType = MtrrType2;
798    }
799    break;
800  case MTRR_CACHE_WRITE_THROUGH:
801    if (
802         MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
803         MtrrType2==MTRR_CACHE_WRITE_BACK
804       ) {
805      MtrrType = MTRR_CACHE_WRITE_THROUGH;
806    } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {
807      MtrrType = MTRR_CACHE_UNCACHEABLE;
808    }
809    break;
810  case MTRR_CACHE_WRITE_PROTECTED:
811    if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||
812        MtrrType2 == MTRR_CACHE_UNCACHEABLE) {
813      MtrrType = MtrrType2;
814    }
815    break;
816  case MTRR_CACHE_WRITE_BACK:
817    if (
818         MtrrType2== MTRR_CACHE_UNCACHEABLE ||
819         MtrrType2==MTRR_CACHE_WRITE_THROUGH ||
820         MtrrType2== MTRR_CACHE_WRITE_BACK
821       ) {
822      MtrrType = MtrrType2;
823    }
824    break;
825  case MTRR_CACHE_INVALID_TYPE:
826    MtrrType = MtrrType2;
827    break;
828  default:
829    break;
830  }
831
832  if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {
833    MtrrType = MtrrType1;
834  }
835  return MtrrType;
836}
837
838
839/**
840  This function attempts to set the attributes for a memory range.
841
842  @param  BaseAddress            The physical address that is the start
843                                 address of a memory region.
844  @param  Length                 The size in bytes of the memory region.
845  @param  Attributes             The bit mask of attributes to set for the
846                                 memory region.
847
848  @retval RETURN_SUCCESS            The attributes were set for the memory
849                                    region.
850  @retval RETURN_INVALID_PARAMETER  Length is zero.
851  @retval RETURN_UNSUPPORTED        The processor does not support one or
852                                    more bytes of the memory resource range
853                                    specified by BaseAddress and Length.
854  @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support
855                                    for the memory resource range specified
856                                    by BaseAddress and Length.
857  @retval RETURN_ACCESS_DENIED      The attributes for the memory resource
858                                    range specified by BaseAddress and Length
859                                    cannot be modified.
860  @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to
861                                    modify the attributes of the memory
862                                    resource range.
863
864**/
865RETURN_STATUS
866EFIAPI
867MtrrSetMemoryAttribute (
868  IN PHYSICAL_ADDRESS        BaseAddress,
869  IN UINT64                  Length,
870  IN MTRR_MEMORY_CACHE_TYPE  Attribute
871  )
872{
873  UINT64                    TempQword;
874  RETURN_STATUS             Status;
875  UINT64                    MemoryType;
876  UINT64                    Remainder;
877  BOOLEAN                   OverLap;
878  BOOLEAN                   Positive;
879  UINT32                    MsrNum;
880  UINTN                     MtrrNumber;
881  VARIABLE_MTRR             VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
882  UINT32                    UsedMtrr;
883  UINT64                    MtrrValidBitsMask;
884  UINT64                    MtrrValidAddressMask;
885  UINTN                     Cr4;
886  BOOLEAN                   OverwriteExistingMtrr;
887  UINT32                    FirmwareVariableMtrrCount;
888  UINT32                    VariableMtrrEnd;
889
890  if (!IsMtrrSupported ()) {
891    return RETURN_UNSUPPORTED;
892  }
893
894  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
895  VariableMtrrEnd = MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (2 * GetVariableMtrrCount ()) - 1;
896
897  MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
898
899  TempQword = 0;
900  MemoryType = (UINT64)Attribute;
901  OverwriteExistingMtrr = FALSE;
902
903  //
904  // Check for an invalid parameter
905  //
906  if (Length == 0) {
907    return RETURN_INVALID_PARAMETER;
908  }
909
910  if (
911       (BaseAddress &~MtrrValidAddressMask) != 0 ||
912       (Length &~MtrrValidAddressMask) != 0
913     ) {
914    return RETURN_UNSUPPORTED;
915  }
916
917  //
918  // Check if Fixed MTRR
919  //
920  Status = RETURN_SUCCESS;
921  while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {
922    Cr4 = PreMtrrChange ();
923    Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length);
924    PostMtrrChange (Cr4);
925    if (RETURN_ERROR (Status)) {
926      return Status;
927    }
928  }
929
930  if (Length == 0) {
931    //
932    // A Length of 0 can only make sense for fixed MTTR ranges.
933    // Since we just handled the fixed MTRRs, we can skip the
934    // variable MTRR section.
935    //
936    goto Done;
937  }
938
939  //
940  // Since memory ranges below 1MB will be overridden by the fixed MTRRs,
941  // we can set the bade to 0 to save variable MTRRs.
942  //
943  if (BaseAddress == BASE_1MB) {
944    BaseAddress = 0;
945    Length += SIZE_1MB;
946  }
947
948  //
949  // Check memory base address alignment
950  //
951  DivU64x64Remainder (BaseAddress, Power2MaxMemory (LShiftU64 (Length, 1)), &Remainder);
952  if (Remainder != 0) {
953    DivU64x64Remainder (BaseAddress, Power2MaxMemory (Length), &Remainder);
954    if (Remainder != 0) {
955      Status = RETURN_UNSUPPORTED;
956      goto Done;
957    }
958  }
959
960  //
961  // Check for overlap
962  //
963  UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr);
964  OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr);
965  if (OverLap) {
966    Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr);
967    if (RETURN_ERROR (Status)) {
968      goto Done;
969    }
970
971    if (Length == 0) {
972      //
973      // Combined successfully
974      //
975      Status = RETURN_SUCCESS;
976      goto Done;
977    }
978  }
979
980  //
981  // Program Variable MTRRs
982  //
983  // Avoid hardcode here and read data dynamically
984  //
985  if (UsedMtrr >= FirmwareVariableMtrrCount) {
986    Status = RETURN_OUT_OF_RESOURCES;
987    goto Done;
988  }
989
990  //
991  // The memory type is the same with the type specified by
992  // MTRR_LIB_IA32_MTRR_DEF_TYPE.
993  //
994  if ((!OverwriteExistingMtrr) && (Attribute == GetMtrrDefaultMemoryType ())) {
995    //
996    // Invalidate the now-unused MTRRs
997    //
998    InvalidateMtrr(VariableMtrr);
999    goto Done;
1000  }
1001
1002  TempQword = Length;
1003
1004
1005  if (TempQword == Power2MaxMemory (TempQword)) {
1006    //
1007    // Invalidate the now-unused MTRRs
1008    //
1009    InvalidateMtrr(VariableMtrr);
1010
1011    //
1012    // Find first unused MTRR
1013    //
1014    for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;
1015         MsrNum < VariableMtrrEnd;
1016         MsrNum += 2
1017        ) {
1018      if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1019        break;
1020      }
1021    }
1022
1023    ProgramVariableMtrr (
1024      MsrNum,
1025      BaseAddress,
1026      Length,
1027      MemoryType,
1028      MtrrValidAddressMask
1029      );
1030  } else {
1031
1032    Positive = GetDirection (TempQword, &MtrrNumber);
1033
1034    if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {
1035      Status = RETURN_OUT_OF_RESOURCES;
1036      goto Done;
1037    }
1038
1039    //
1040    // Invalidate the now-unused MTRRs
1041    //
1042    InvalidateMtrr(VariableMtrr);
1043
1044    //
1045    // Find first unused MTRR
1046    //
1047    for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;
1048         MsrNum < VariableMtrrEnd;
1049         MsrNum += 2
1050        ) {
1051      if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1052        break;
1053      }
1054    }
1055
1056    if (!Positive) {
1057      Length = Power2MaxMemory (LShiftU64 (TempQword, 1));
1058      ProgramVariableMtrr (
1059        MsrNum,
1060        BaseAddress,
1061        Length,
1062        MemoryType,
1063        MtrrValidAddressMask
1064        );
1065      BaseAddress += Length;
1066      TempQword   = Length - TempQword;
1067      MemoryType  = MTRR_CACHE_UNCACHEABLE;
1068    }
1069
1070    do {
1071      //
1072      // Find unused MTRR
1073      //
1074      for (; MsrNum < VariableMtrrEnd; MsrNum += 2) {
1075        if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1076          break;
1077        }
1078      }
1079
1080      Length = Power2MaxMemory (TempQword);
1081      if (!Positive) {
1082        BaseAddress -= Length;
1083      }
1084
1085      ProgramVariableMtrr (
1086        MsrNum,
1087        BaseAddress,
1088        Length,
1089        MemoryType,
1090        MtrrValidAddressMask
1091        );
1092
1093      if (Positive) {
1094        BaseAddress += Length;
1095      }
1096      TempQword -= Length;
1097
1098    } while (TempQword > 0);
1099  }
1100
1101Done:
1102  return Status;
1103
1104}
1105
1106
1107/**
1108  This function will get the memory cache type of the specific address.
1109
1110  This function is mainly for debug purpose.
1111
1112  @param  Address   The specific address
1113
1114  @return Memory cache type of the sepcific address
1115
1116**/
1117MTRR_MEMORY_CACHE_TYPE
1118EFIAPI
1119MtrrGetMemoryAttribute (
1120  IN PHYSICAL_ADDRESS   Address
1121  )
1122{
1123  UINT64                  TempQword;
1124  UINTN                   Index;
1125  UINTN                   SubIndex;
1126  UINT64                  MtrrType;
1127  UINT64                  TempMtrrType;
1128  MTRR_MEMORY_CACHE_TYPE  CacheType;
1129  VARIABLE_MTRR           VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
1130  UINT64                  MtrrValidBitsMask;
1131  UINT64                  MtrrValidAddressMask;
1132  UINTN                   VariableMtrrCount;
1133
1134  if (!IsMtrrSupported ()) {
1135    return CacheUncacheable;
1136  }
1137
1138  //
1139  // Check if MTRR is enabled, if not, return UC as attribute
1140  //
1141  TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
1142  MtrrType = MTRR_CACHE_INVALID_TYPE;
1143
1144  if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {
1145    return CacheUncacheable;
1146  }
1147
1148  //
1149  // If address is less than 1M, then try to go through the fixed MTRR
1150  //
1151  if (Address < BASE_1MB) {
1152    if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {
1153      //
1154      // Go through the fixed MTRR
1155      //
1156      for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1157         if (Address >= MtrrLibFixedMtrrTable[Index].BaseAddress &&
1158             Address  < (
1159                          MtrrLibFixedMtrrTable[Index].BaseAddress +
1160                          (MtrrLibFixedMtrrTable[Index].Length * 8)
1161                        )
1162            ) {
1163           SubIndex =
1164             ((UINTN)Address - MtrrLibFixedMtrrTable[Index].BaseAddress) /
1165               MtrrLibFixedMtrrTable[Index].Length;
1166           TempQword = AsmReadMsr64 (MtrrLibFixedMtrrTable[Index].Msr);
1167           MtrrType =  RShiftU64 (TempQword, SubIndex * 8) & 0xFF;
1168           return GetMemoryCacheTypeFromMtrrType (MtrrType);
1169         }
1170      }
1171    }
1172  }
1173  MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);
1174  MtrrGetMemoryAttributeInVariableMtrr(
1175    MtrrValidBitsMask,
1176    MtrrValidAddressMask,
1177    VariableMtrr
1178    );
1179
1180  //
1181  // Go through the variable MTRR
1182  //
1183  VariableMtrrCount = GetVariableMtrrCount ();
1184  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1185
1186  for (Index = 0; Index < VariableMtrrCount; Index++) {
1187    if (VariableMtrr[Index].Valid) {
1188      if (Address >= VariableMtrr[Index].BaseAddress &&
1189          Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {
1190        TempMtrrType = VariableMtrr[Index].Type;
1191        MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);
1192      }
1193    }
1194  }
1195  CacheType = GetMemoryCacheTypeFromMtrrType (MtrrType);
1196
1197  return CacheType;
1198}
1199
1200
1201/**
1202  This function will get the raw value in variable MTRRs
1203
1204  @param  VariableSettings   A buffer to hold variable MTRRs content.
1205
1206  @return The VariableSettings input pointer
1207
1208**/
1209MTRR_VARIABLE_SETTINGS*
1210EFIAPI
1211MtrrGetVariableMtrr (
1212  OUT MTRR_VARIABLE_SETTINGS         *VariableSettings
1213  )
1214{
1215  UINT32  Index;
1216  UINT32  VariableMtrrCount;
1217
1218  if (!IsMtrrSupported ()) {
1219    return VariableSettings;
1220  }
1221
1222  VariableMtrrCount = GetVariableMtrrCount ();
1223  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1224
1225  for (Index = 0; Index < VariableMtrrCount; Index++) {
1226    VariableSettings->Mtrr[Index].Base =
1227      AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));
1228    VariableSettings->Mtrr[Index].Mask =
1229      AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);
1230  }
1231
1232  return  VariableSettings;
1233}
1234
1235
1236/**
1237  Worker function setting variable MTRRs
1238
1239  @param  VariableSettings   A buffer to hold variable MTRRs content.
1240
1241**/
1242VOID
1243MtrrSetVariableMtrrWorker (
1244  IN MTRR_VARIABLE_SETTINGS         *VariableSettings
1245  )
1246{
1247  UINT32  Index;
1248  UINT32  VariableMtrrCount;
1249
1250  VariableMtrrCount = GetVariableMtrrCount ();
1251  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
1252
1253  for (Index = 0; Index < VariableMtrrCount; Index++) {
1254    AsmWriteMsr64 (
1255      MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),
1256      VariableSettings->Mtrr[Index].Base
1257      );
1258    AsmWriteMsr64 (
1259      MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,
1260      VariableSettings->Mtrr[Index].Mask
1261      );
1262  }
1263}
1264
1265
1266/**
1267  This function sets variable MTRRs
1268
1269  @param  VariableSettings   A buffer to hold variable MTRRs content.
1270
1271  @return The pointer of VariableSettings
1272
1273**/
1274MTRR_VARIABLE_SETTINGS*
1275EFIAPI
1276MtrrSetVariableMtrr (
1277  IN MTRR_VARIABLE_SETTINGS         *VariableSettings
1278  )
1279{
1280  UINTN  Cr4;
1281
1282  if (!IsMtrrSupported ()) {
1283    return VariableSettings;
1284  }
1285
1286  Cr4 = PreMtrrChange ();
1287  MtrrSetVariableMtrrWorker (VariableSettings);
1288  PostMtrrChange (Cr4);
1289  return  VariableSettings;
1290}
1291
1292
1293/**
1294  This function gets the content in fixed MTRRs
1295
1296  @param  FixedSettings  A buffer to hold fixed Mtrrs content.
1297
1298  @retval The pointer of FixedSettings
1299
1300**/
1301MTRR_FIXED_SETTINGS*
1302EFIAPI
1303MtrrGetFixedMtrr (
1304  OUT MTRR_FIXED_SETTINGS         *FixedSettings
1305  )
1306{
1307  UINT32  Index;
1308
1309  if (!IsMtrrSupported ()) {
1310    return FixedSettings;
1311  }
1312
1313  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1314      FixedSettings->Mtrr[Index] =
1315        AsmReadMsr64 (MtrrLibFixedMtrrTable[Index].Msr);
1316  };
1317
1318  return FixedSettings;
1319}
1320
1321/**
1322  Worker function setting fixed MTRRs
1323
1324  @param  FixedSettings  A buffer to hold fixed Mtrrs content.
1325
1326**/
1327VOID
1328MtrrSetFixedMtrrWorker (
1329  IN MTRR_FIXED_SETTINGS          *FixedSettings
1330  )
1331{
1332  UINT32  Index;
1333
1334  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1335     AsmWriteMsr64 (
1336       MtrrLibFixedMtrrTable[Index].Msr,
1337       FixedSettings->Mtrr[Index]
1338       );
1339  }
1340}
1341
1342
1343/**
1344  This function sets fixed MTRRs
1345
1346  @param  FixedSettings  A buffer to hold fixed Mtrrs content.
1347
1348  @retval The pointer of FixedSettings
1349
1350**/
1351MTRR_FIXED_SETTINGS*
1352EFIAPI
1353MtrrSetFixedMtrr (
1354  IN MTRR_FIXED_SETTINGS          *FixedSettings
1355  )
1356{
1357  UINTN  Cr4;
1358
1359  if (!IsMtrrSupported ()) {
1360    return FixedSettings;
1361  }
1362
1363  Cr4 = PreMtrrChange ();
1364  MtrrSetFixedMtrrWorker (FixedSettings);
1365  PostMtrrChange (Cr4);
1366
1367  return FixedSettings;
1368}
1369
1370
1371/**
1372  This function gets the content in all MTRRs (variable and fixed)
1373
1374  @param  MtrrSetting  A buffer to hold all Mtrrs content.
1375
1376  @retval the pointer of MtrrSetting
1377
1378**/
1379MTRR_SETTINGS *
1380EFIAPI
1381MtrrGetAllMtrrs (
1382  OUT MTRR_SETTINGS                *MtrrSetting
1383  )
1384{
1385  if (!IsMtrrSupported ()) {
1386    return MtrrSetting;
1387  }
1388
1389  //
1390  // Get fixed MTRRs
1391  //
1392  MtrrGetFixedMtrr (&MtrrSetting->Fixed);
1393
1394  //
1395  // Get variable MTRRs
1396  //
1397  MtrrGetVariableMtrr (&MtrrSetting->Variables);
1398
1399  //
1400  // Get MTRR_DEF_TYPE value
1401  //
1402  MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);
1403
1404  return MtrrSetting;
1405}
1406
1407
1408/**
1409  This function sets all MTRRs (variable and fixed)
1410
1411  @param  MtrrSetting  A buffer holding all MTRRs content.
1412
1413  @retval The pointer of MtrrSetting
1414
1415**/
1416MTRR_SETTINGS *
1417EFIAPI
1418MtrrSetAllMtrrs (
1419  IN MTRR_SETTINGS                *MtrrSetting
1420  )
1421{
1422  UINTN  Cr4;
1423
1424  if (!IsMtrrSupported ()) {
1425    return MtrrSetting;
1426  }
1427
1428  Cr4 = PreMtrrChange ();
1429
1430  //
1431  // Set fixed MTRRs
1432  //
1433  MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
1434
1435  //
1436  // Set variable MTRRs
1437  //
1438  MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
1439
1440  //
1441  // Set MTRR_DEF_TYPE value
1442  //
1443  AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
1444
1445  PostMtrrChange (Cr4);
1446
1447  return MtrrSetting;
1448}
1449
1450
1451/**
1452  This function prints all MTRRs for debugging.
1453**/
1454VOID
1455MtrrDebugPrintAllMtrrs (
1456  )
1457{
1458  DEBUG_CODE (
1459    {
1460      MTRR_SETTINGS  MtrrSettings;
1461      UINTN          Index;
1462      UINTN          VariableMtrrCount;
1463
1464      if (!IsMtrrSupported ()) {
1465        return;
1466      }
1467
1468      MtrrGetAllMtrrs (&MtrrSettings);
1469      DEBUG((EFI_D_ERROR, "DefaultType = %016lx\n", MtrrSettings.MtrrDefType));
1470      for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1471        DEBUG((
1472          EFI_D_ERROR, "Fixed[%02d] = %016lx\n",
1473          Index,
1474          MtrrSettings.Fixed.Mtrr[Index]
1475          ));
1476      }
1477
1478      VariableMtrrCount = GetVariableMtrrCount ();
1479      for (Index = 0; Index < VariableMtrrCount; Index++) {
1480        DEBUG((
1481          EFI_D_ERROR, "Variable[%02d] = %016lx, %016lx\n",
1482          Index,
1483          MtrrSettings.Variables.Mtrr[Index].Base,
1484          MtrrSettings.Variables.Mtrr[Index].Mask
1485          ));
1486      }
1487    }
1488  );
1489}
1490
1491/**
1492  Checks if MTRR is supported.
1493
1494  @retval TRUE  MTRR is supported.
1495  @retval FALSE MTRR is not supported.
1496
1497**/
1498BOOLEAN
1499EFIAPI
1500IsMtrrSupported (
1501  VOID
1502  )
1503{
1504  UINT32  RegEdx;
1505  UINT64  MtrrCap;
1506
1507  //
1508  // Check CPUID(1).EDX[12] for MTRR capability
1509  //
1510  AsmCpuid (1, NULL, NULL, NULL, &RegEdx);
1511  if (BitFieldRead32 (RegEdx, 12, 12) == 0) {
1512    return FALSE;
1513  }
1514
1515  //
1516  // Check IA32_MTRRCAP.[0..7] for number of variable MTRRs and IA32_MTRRCAP[8] for
1517  // fixed MTRRs existence. If number of variable MTRRs is zero, or fixed MTRRs do not
1518  // exist, return false.
1519  //
1520  MtrrCap = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_CAP);
1521  if  ((BitFieldRead64 (MtrrCap, 0, 7) == 0) || (BitFieldRead64 (MtrrCap, 8, 8) == 0)) {
1522    return FALSE;
1523  }
1524
1525  return TRUE;
1526}
1527