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