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