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