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