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