]> git.proxmox.com Git - mirror_edk2.git/blobdiff - QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c
QuarkSocPkg: Add new package for Quark SoC X1000
[mirror_edk2.git] / QuarkSocPkg / QuarkNorthCluster / Library / MtrrLib / MtrrLib.c
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c b/QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.c
new file mode 100644 (file)
index 0000000..4a88dff
--- /dev/null
@@ -0,0 +1,2117 @@
+/** @file\r
+MTRR setting library\r
+\r
+Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Base.h>\r
+\r
+#include <Library/MtrrLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/CpuLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/QNCAccessLib.h>\r
+\r
+#define QUARK_SOC_CPUID_FAMILY_MODEL_STEPPING         0x590\r
+\r
+//\r
+// Context to save and restore when MTRRs are programmed\r
+//\r
+typedef struct {\r
+  UINTN    Cr4;\r
+  BOOLEAN  InterruptState;\r
+} MTRR_CONTEXT;\r
+\r
+//\r
+// This table defines the offset, base and length of the fixed MTRRs\r
+//\r
+CONST FIXED_MTRR  mMtrrLibFixedMtrrTable[] = {\r
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000, 0,       SIZE_64KB },\r
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_80000, 0x80000, SIZE_16KB },\r
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_A0000, 0xA0000, SIZE_16KB },\r
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C0000,  0xC0000, SIZE_4KB  },\r
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C8000,  0xC8000, SIZE_4KB  },\r
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D0000,  0xD0000, SIZE_4KB  },\r
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D8000,  0xD8000, SIZE_4KB  },\r
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E0000,  0xE0000, SIZE_4KB  },\r
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E8000,  0xE8000, SIZE_4KB  },\r
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F0000,  0xF0000, SIZE_4KB  },\r
+  { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000,  0xF8000, SIZE_4KB  }\r
+};\r
+\r
+//\r
+// Lookup table used to print MTRRs\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {\r
+  "UC",  // CacheUncacheable\r
+  "WC",  // CacheWriteCombining\r
+  "R*",  // Invalid\r
+  "R*",  // Invalid\r
+  "WT",  // CacheWriteThrough\r
+  "WP",  // CacheWriteProtected\r
+  "WB",  // CacheWriteBack\r
+  "R*"   // Invalid\r
+};\r
+\r
+UINT64\r
+MtrrRegisterRead (\r
+  IN  UINT32  MtrrRegister\r
+  )\r
+{\r
+  UINT64  Result;\r
+\r
+  Result = (UINT64)QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister);\r
+  if (MtrrRegister >= QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000 && MtrrRegister <= QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000) {\r
+    Result = Result | LShiftU64 ((UINT64)QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister + 1), 32);\r
+  }\r
+  return Result;\r
+}\r
+\r
+UINT64\r
+MtrrRegisterWrite (\r
+  IN  UINT32  MtrrRegister,\r
+  IN  UINT64  Value\r
+  )\r
+{\r
+  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister, (UINT32)Value);\r
+  if (MtrrRegister >= QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000 && MtrrRegister <= QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000) {\r
+    QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister + 1, (UINT32)RShiftU64 (Value, 32));\r
+  }\r
+  return Value;\r
+}\r
+\r
+UINT64\r
+MtrrRegisterBitFieldWrite (\r
+  IN  UINT32  MtrrRegister,\r
+  IN  UINTN   StartBit,\r
+  IN  UINTN   EndBit,\r
+  IN  UINT64  Value\r
+  )\r
+{\r
+  return MtrrRegisterWrite (\r
+           MtrrRegister,\r
+           BitFieldWrite64 (\r
+             MtrrRegisterRead (MtrrRegister),\r
+             StartBit,\r
+             EndBit,\r
+             Value\r
+             )\r
+           );\r
+}\r
+\r
+/**\r
+  Worker function returns the variable MTRR count for the CPU.\r
+\r
+  @return Variable MTRR count\r
+\r
+**/\r
+UINT32\r
+GetVariableMtrrCountWorker (\r
+  VOID\r
+  )\r
+{\r
+  UINT32  VariableMtrrCount;\r
+\r
+  VariableMtrrCount = (UINT32)(MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);\r
+  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+  return VariableMtrrCount;\r
+}\r
+\r
+/**\r
+  Returns the variable MTRR count for the CPU.\r
+\r
+  @return Variable MTRR count\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetVariableMtrrCount (\r
+  VOID\r
+  )\r
+{\r
+  if (!IsMtrrSupported ()) {\r
+    return 0;\r
+  }\r
+  return GetVariableMtrrCountWorker ();\r
+}\r
+\r
+/**\r
+  Worker function returns the firmware usable variable MTRR count for the CPU.\r
+\r
+  @return Firmware usable variable MTRR count\r
+\r
+**/\r
+UINT32\r
+GetFirmwareVariableMtrrCountWorker (\r
+  VOID\r
+  )\r
+{\r
+  UINT32  VariableMtrrCount;\r
+  UINT32  ReservedMtrrNumber;\r
+\r
+  VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+  ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);\r
+  if (VariableMtrrCount < ReservedMtrrNumber) {\r
+    return 0;\r
+  }\r
+\r
+  return VariableMtrrCount - ReservedMtrrNumber;\r
+}\r
+\r
+/**\r
+  Returns the firmware usable variable MTRR count for the CPU.\r
+\r
+  @return Firmware usable variable MTRR count\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetFirmwareVariableMtrrCount (\r
+  VOID\r
+  )\r
+{\r
+  if (!IsMtrrSupported ()) {\r
+    return 0;\r
+  }\r
+  return GetFirmwareVariableMtrrCountWorker ();\r
+}\r
+\r
+/**\r
+  Worker function returns the default MTRR cache type for the system.\r
+\r
+  If MtrrSetting is not NULL, returns the default MTRR cache type from input\r
+  MTRR settings buffer.\r
+  If MtrrSetting is NULL, returns the default MTRR cache type from MSR.\r
+\r
+  @param[in]  MtrrSetting    A buffer holding all MTRRs content.\r
+\r
+  @return  The default MTRR cache type.\r
+\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+MtrrGetDefaultMemoryTypeWorker (\r
+  IN MTRR_SETTINGS      *MtrrSetting\r
+  )\r
+{\r
+  if (MtrrSetting == NULL) {\r
+    return (MTRR_MEMORY_CACHE_TYPE) (MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE) & 0x7);\r
+  } else {\r
+    return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Returns the default MTRR cache type for the system.\r
+\r
+  @return  The default MTRR cache type.\r
+\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+EFIAPI\r
+MtrrGetDefaultMemoryType (\r
+  VOID\r
+  )\r
+{\r
+  if (!IsMtrrSupported ()) {\r
+    return CacheUncacheable;\r
+  }\r
+  return MtrrGetDefaultMemoryTypeWorker (NULL);\r
+}\r
+\r
+/**\r
+  Preparation before programming MTRR.\r
+\r
+  This function will do some preparation for programming MTRRs:\r
+  disable cache, invalid cache and disable MTRR caching functionality\r
+\r
+  @param[out] MtrrContext  Pointer to context to save\r
+\r
+**/\r
+VOID\r
+PreMtrrChange (\r
+  OUT MTRR_CONTEXT  *MtrrContext\r
+  )\r
+{\r
+  //\r
+  // Disable interrupts and save current interrupt state\r
+  //\r
+  MtrrContext->InterruptState = SaveAndDisableInterrupts();\r
+\r
+  //\r
+  // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)\r
+  //\r
+  AsmDisableCache ();\r
+\r
+  //\r
+  // Save original CR4 value and clear PGE flag (Bit 7)\r
+  //\r
+  MtrrContext->Cr4 = AsmReadCr4 ();\r
+  AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));\r
+\r
+  //\r
+  // Flush all TLBs\r
+  //\r
+  CpuFlushTlb ();\r
+\r
+  //\r
+  // Disable MTRRs\r
+  //\r
+  MtrrRegisterBitFieldWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, 10, 11, 0);\r
+}\r
+\r
+/**\r
+  Cleaning up after programming MTRRs.\r
+\r
+  This function will do some clean up after programming MTRRs:\r
+  Flush all TLBs,  re-enable caching, restore CR4.\r
+\r
+  @param[in] MtrrContext  Pointer to context to restore\r
+\r
+**/\r
+VOID\r
+PostMtrrChangeEnableCache (\r
+  IN MTRR_CONTEXT  *MtrrContext\r
+  )\r
+{\r
+  //\r
+  // Flush all TLBs\r
+  //\r
+  CpuFlushTlb ();\r
+\r
+  //\r
+  // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)\r
+  //\r
+  AsmEnableCache ();\r
+\r
+  //\r
+  // Restore original CR4 value\r
+  //\r
+  AsmWriteCr4 (MtrrContext->Cr4);\r
+\r
+  //\r
+  // Restore original interrupt state\r
+  //\r
+  SetInterruptState (MtrrContext->InterruptState);\r
+}\r
+\r
+/**\r
+  Cleaning up after programming MTRRs.\r
+\r
+  This function will do some clean up after programming MTRRs:\r
+  enable MTRR caching functionality, and enable cache\r
+\r
+  @param[in] MtrrContext  Pointer to context to restore\r
+\r
+**/\r
+VOID\r
+PostMtrrChange (\r
+  IN MTRR_CONTEXT  *MtrrContext\r
+  )\r
+{\r
+  //\r
+  // Enable Cache MTRR\r
+  //\r
+  MtrrRegisterBitFieldWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, 10, 11, 3);\r
+\r
+  PostMtrrChangeEnableCache (MtrrContext);\r
+}\r
+\r
+/**\r
+  Worker function gets the content in fixed MTRRs\r
+\r
+  @param[out]  FixedSettings  A buffer to hold fixed MTRRs content.\r
+\r
+  @retval The pointer of FixedSettings\r
+\r
+**/\r
+MTRR_FIXED_SETTINGS*\r
+MtrrGetFixedMtrrWorker (\r
+  OUT MTRR_FIXED_SETTINGS         *FixedSettings\r
+  )\r
+{\r
+  UINT32  Index;\r
+\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+      FixedSettings->Mtrr[Index] =\r
+        MtrrRegisterRead (mMtrrLibFixedMtrrTable[Index].Msr);\r
+  }\r
+\r
+  return FixedSettings;\r
+}\r
+\r
+\r
+/**\r
+  This function gets the content in fixed MTRRs\r
+\r
+  @param[out]  FixedSettings  A buffer to hold fixed MTRRs content.\r
+\r
+  @retval The pointer of FixedSettings\r
+\r
+**/\r
+MTRR_FIXED_SETTINGS*\r
+EFIAPI\r
+MtrrGetFixedMtrr (\r
+  OUT MTRR_FIXED_SETTINGS         *FixedSettings\r
+  )\r
+{\r
+  if (!IsMtrrSupported ()) {\r
+    return FixedSettings;\r
+  }\r
+\r
+  return MtrrGetFixedMtrrWorker (FixedSettings);\r
+}\r
+\r
+\r
+/**\r
+  Worker function will get the raw value in variable MTRRs\r
+\r
+  If MtrrSetting is not NULL, gets the variable MTRRs raw value from input\r
+  MTRR settings buffer.\r
+  If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.\r
+\r
+  @param[in]  MtrrSetting        A buffer holding all MTRRs content.\r
+  @param[in]  VariableMtrrCount  Number of variable MTRRs.\r
+  @param[out] VariableSettings   A buffer to hold variable MTRRs content.\r
+\r
+  @return The VariableSettings input pointer\r
+\r
+**/\r
+MTRR_VARIABLE_SETTINGS*\r
+MtrrGetVariableMtrrWorker (\r
+  IN  MTRR_SETTINGS           *MtrrSetting,\r
+  IN  UINT32                  VariableMtrrCount,\r
+  OUT MTRR_VARIABLE_SETTINGS  *VariableSettings\r
+  )\r
+{\r
+  UINT32  Index;\r
+\r
+  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+    if (MtrrSetting == NULL) {\r
+      VariableSettings->Mtrr[Index].Base =\r
+        MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1));\r
+      VariableSettings->Mtrr[Index].Mask =\r
+        MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1);\r
+    } else {\r
+      VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;\r
+      VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;\r
+    }\r
+  }\r
+\r
+  return  VariableSettings;\r
+}\r
+\r
+/**\r
+  This function will get the raw value in variable MTRRs\r
+\r
+  @param[out]  VariableSettings   A buffer to hold variable MTRRs content.\r
+\r
+  @return The VariableSettings input pointer\r
+\r
+**/\r
+MTRR_VARIABLE_SETTINGS*\r
+EFIAPI\r
+MtrrGetVariableMtrr (\r
+  OUT MTRR_VARIABLE_SETTINGS         *VariableSettings\r
+  )\r
+{\r
+  if (!IsMtrrSupported ()) {\r
+    return VariableSettings;\r
+  }\r
+\r
+  return MtrrGetVariableMtrrWorker (\r
+           NULL,\r
+           GetVariableMtrrCountWorker (),\r
+           VariableSettings\r
+           );\r
+}\r
+\r
+/**\r
+  Programs fixed MTRRs registers.\r
+\r
+  @param[in]      MemoryCacheType  The memory type to set.\r
+  @param[in, out] Base             The base address of memory range.\r
+  @param[in, out] Length           The length of memory range.\r
+  @param[out]     ReturnMsrNum     The index of the fixed MTRR MSR to program.\r
+  @param[out]     ReturnClearMask  The bits to clear in the fixed MTRR MSR.\r
+  @param[out]     ReturnOrMask     The bits to set in the fixed MTRR MSR.\r
+\r
+  @retval RETURN_SUCCESS      The cache type was updated successfully\r
+  @retval RETURN_UNSUPPORTED  The requested range or cache type was invalid\r
+                              for the fixed MTRRs.\r
+\r
+**/\r
+RETURN_STATUS\r
+ProgramFixedMtrr (\r
+  IN     UINT64               MemoryCacheType,\r
+  IN OUT UINT64               *Base,\r
+  IN OUT UINT64               *Length,\r
+  OUT    UINT32               *ReturnMsrNum,\r
+  OUT    UINT64               *ReturnClearMask,\r
+  OUT    UINT64               *ReturnOrMask\r
+  )\r
+{\r
+  UINT32  MsrNum;\r
+  UINT32  ByteShift;\r
+  UINT64  TempQword;\r
+  UINT64  OrMask;\r
+  UINT64  ClearMask;\r
+\r
+  TempQword = 0;\r
+  OrMask    = 0;\r
+  ClearMask = 0;\r
+\r
+  for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {\r
+    if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&\r
+        (*Base <\r
+            (\r
+              mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
+              (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
+            )\r
+          )\r
+        ) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // We found the fixed MTRR to be programmed\r
+  //\r
+  for (ByteShift = 0; ByteShift < 8; ByteShift++) {\r
+    if (*Base ==\r
+         (\r
+           mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
+           (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
+         )\r
+       ) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (ByteShift == 8) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  for (\r
+        ;\r
+        ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length));\r
+        ByteShift++\r
+      ) {\r
+    OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));\r
+    ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));\r
+    *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length;\r
+    *Base += mMtrrLibFixedMtrrTable[MsrNum].Length;\r
+  }\r
+\r
+  if (ByteShift < 8 && (*Length != 0)) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  *ReturnMsrNum    = MsrNum;\r
+  *ReturnClearMask = ClearMask;\r
+  *ReturnOrMask    = OrMask;\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Worker function gets the attribute of variable MTRRs.\r
+\r
+  This function shadows the content of variable MTRRs into an\r
+  internal array: VariableMtrr.\r
+\r
+  @param[in]   VariableSettings           The variable MTRR values to shadow\r
+  @param[in]   FirmwareVariableMtrrCount  The number of variable MTRRs available to firmware\r
+  @param[in]   MtrrValidBitsMask          The mask for the valid bit of the MTRR\r
+  @param[in]   MtrrValidAddressMask       The valid address mask for MTRR\r
+  @param[out]  VariableMtrr               The array to shadow variable MTRRs content\r
+\r
+  @return                       The return value of this parameter indicates the\r
+                                number of MTRRs which has been used.\r
+\r
+**/\r
+UINT32\r
+MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+  IN  MTRR_VARIABLE_SETTINGS  *VariableSettings,\r
+  IN  UINTN                   FirmwareVariableMtrrCount,\r
+  IN  UINT64                  MtrrValidBitsMask,\r
+  IN  UINT64                  MtrrValidAddressMask,\r
+  OUT VARIABLE_MTRR           *VariableMtrr\r
+  )\r
+{\r
+  UINTN   Index;\r
+  UINT32  UsedMtrr;\r
+\r
+  ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+  for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
+    if ((VariableSettings->Mtrr[Index].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
+      VariableMtrr[Index].Msr         = (UINT32)Index;\r
+      VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);\r
+      VariableMtrr[Index].Length      = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
+      VariableMtrr[Index].Type        = (VariableSettings->Mtrr[Index].Base & 0x0ff);\r
+      VariableMtrr[Index].Valid       = TRUE;\r
+      VariableMtrr[Index].Used        = TRUE;\r
+      UsedMtrr++;\r
+    }\r
+  }\r
+  return UsedMtrr;\r
+}\r
+\r
+\r
+/**\r
+  Gets the attribute of variable MTRRs.\r
+\r
+  This function shadows the content of variable MTRRs into an\r
+  internal array: VariableMtrr.\r
+\r
+  @param[in]   MtrrValidBitsMask     The mask for the valid bit of the MTRR\r
+  @param[in]   MtrrValidAddressMask  The valid address mask for MTRR\r
+  @param[out]  VariableMtrr          The array to shadow variable MTRRs content\r
+\r
+  @return                       The return value of this paramter indicates the\r
+                                number of MTRRs which has been used.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+MtrrGetMemoryAttributeInVariableMtrr (\r
+  IN  UINT64                    MtrrValidBitsMask,\r
+  IN  UINT64                    MtrrValidAddressMask,\r
+  OUT VARIABLE_MTRR             *VariableMtrr\r
+  )\r
+{\r
+  MTRR_VARIABLE_SETTINGS  VariableSettings;\r
+\r
+  if (!IsMtrrSupported ()) {\r
+    return 0;\r
+  }\r
+\r
+  MtrrGetVariableMtrrWorker (\r
+    NULL,\r
+    GetVariableMtrrCountWorker (),\r
+    &VariableSettings\r
+    );\r
+\r
+  return MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+           &VariableSettings,\r
+           GetFirmwareVariableMtrrCountWorker (),\r
+           MtrrValidBitsMask,\r
+           MtrrValidAddressMask,\r
+           VariableMtrr\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Checks overlap between given memory range and MTRRs.\r
+\r
+  @param[in]  FirmwareVariableMtrrCount  The number of variable MTRRs available\r
+                                         to firmware.\r
+  @param[in]  Start                      The start address of memory range.\r
+  @param[in]  End                        The end address of memory range.\r
+  @param[in]  VariableMtrr               The array to shadow variable MTRRs content\r
+\r
+  @retval TRUE             Overlap exists.\r
+  @retval FALSE            No overlap.\r
+\r
+**/\r
+BOOLEAN\r
+CheckMemoryAttributeOverlap (\r
+  IN UINTN             FirmwareVariableMtrrCount,\r
+  IN PHYSICAL_ADDRESS  Start,\r
+  IN PHYSICAL_ADDRESS  End,\r
+  IN VARIABLE_MTRR     *VariableMtrr\r
+  )\r
+{\r
+  UINT32  Index;\r
+\r
+  for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
+    if (\r
+         VariableMtrr[Index].Valid &&\r
+         !(\r
+           (Start > (VariableMtrr[Index].BaseAddress +\r
+                     VariableMtrr[Index].Length - 1)\r
+           ) ||\r
+           (End < VariableMtrr[Index].BaseAddress)\r
+         )\r
+       ) {\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Marks a variable MTRR as non-valid.\r
+\r
+  @param[in]   Index         The index of the array VariableMtrr to be invalidated\r
+  @param[in]   VariableMtrr  The array to shadow variable MTRRs content\r
+  @param[out]  UsedMtrr      The number of MTRRs which has already been used\r
+\r
+**/\r
+VOID\r
+InvalidateShadowMtrr (\r
+  IN   UINTN              Index,\r
+  IN   VARIABLE_MTRR      *VariableMtrr,\r
+  OUT  UINT32             *UsedMtrr\r
+  )\r
+{\r
+  VariableMtrr[Index].Valid = FALSE;\r
+  *UsedMtrr = *UsedMtrr - 1;\r
+}\r
+\r
+\r
+/**\r
+  Combines memory attributes.\r
+\r
+  If overlap exists between given memory range and MTRRs, try to combine them.\r
+\r
+  @param[in]       FirmwareVariableMtrrCount  The number of variable MTRRs\r
+                                              available to firmware.\r
+  @param[in]       Attributes                 The memory type to set.\r
+  @param[in, out]  Base                       The base address of memory range.\r
+  @param[in, out]  Length                     The length of memory range.\r
+  @param[in]       VariableMtrr               The array to shadow variable MTRRs content\r
+  @param[in, out]  UsedMtrr                   The number of MTRRs which has already been used\r
+  @param[out]      OverwriteExistingMtrr      Returns whether an existing MTRR was used\r
+\r
+  @retval EFI_SUCCESS            Memory region successfully combined.\r
+  @retval EFI_ACCESS_DENIED      Memory region cannot be combined.\r
+\r
+**/\r
+RETURN_STATUS\r
+CombineMemoryAttribute (\r
+  IN     UINT32             FirmwareVariableMtrrCount,\r
+  IN     UINT64             Attributes,\r
+  IN OUT UINT64             *Base,\r
+  IN OUT UINT64             *Length,\r
+  IN     VARIABLE_MTRR      *VariableMtrr,\r
+  IN OUT UINT32             *UsedMtrr,\r
+  OUT    BOOLEAN            *OverwriteExistingMtrr\r
+  )\r
+{\r
+  UINT32  Index;\r
+  UINT64  CombineStart;\r
+  UINT64  CombineEnd;\r
+  UINT64  MtrrEnd;\r
+  UINT64  EndAddress;\r
+  BOOLEAN CoveredByExistingMtrr;\r
+\r
+  *OverwriteExistingMtrr = FALSE;\r
+  CoveredByExistingMtrr = FALSE;\r
+  EndAddress = *Base +*Length - 1;\r
+\r
+  for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
+\r
+    MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;\r
+    if (\r
+         !VariableMtrr[Index].Valid ||\r
+         (\r
+           *Base > (MtrrEnd) ||\r
+           (EndAddress < VariableMtrr[Index].BaseAddress)\r
+         )\r
+       ) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Combine same attribute MTRR range\r
+    //\r
+    if (Attributes == VariableMtrr[Index].Type) {\r
+      //\r
+      // if the MTRR range contain the request range, set a flag, then continue to\r
+      // invalidate any MTRR of the same request range with higher priority cache type.\r
+      //\r
+      if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {\r
+        CoveredByExistingMtrr = TRUE;\r
+        continue;\r
+      }\r
+      //\r
+      // invalid this MTRR, and program the combine range\r
+      //\r
+      CombineStart  =\r
+        (*Base) < VariableMtrr[Index].BaseAddress ?\r
+          (*Base) :\r
+          VariableMtrr[Index].BaseAddress;\r
+      CombineEnd    = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;\r
+\r
+      //\r
+      // Record the MTRR usage status in VariableMtrr array.\r
+      //\r
+      InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
+      *Base       = CombineStart;\r
+      *Length     = CombineEnd - CombineStart + 1;\r
+      EndAddress  = CombineEnd;\r
+      *OverwriteExistingMtrr = TRUE;\r
+      continue;\r
+    } else {\r
+      //\r
+      // The cache type is different, but the range is convered by one MTRR\r
+      //\r
+      if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {\r
+        InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
+        continue;\r
+      }\r
+\r
+    }\r
+\r
+    if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&\r
+         VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||\r
+        (Attributes == MTRR_CACHE_WRITE_BACK &&\r
+         VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||\r
+        (Attributes == MTRR_CACHE_UNCACHEABLE) ||\r
+        (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)\r
+     ) {\r
+      *OverwriteExistingMtrr = TRUE;\r
+      continue;\r
+    }\r
+    //\r
+    // Other type memory overlap is invalid\r
+    //\r
+    return RETURN_ACCESS_DENIED;\r
+  }\r
+\r
+  if (CoveredByExistingMtrr) {\r
+    *Length = 0;\r
+  }\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Calculates the maximum value which is a power of 2, but less the MemoryLength.\r
+\r
+  @param[in]  MemoryLength        The number to pass in.\r
+\r
+  @return The maximum value which is align to power of 2 and less the MemoryLength\r
+\r
+**/\r
+UINT64\r
+Power2MaxMemory (\r
+  IN UINT64                     MemoryLength\r
+  )\r
+{\r
+  UINT64  Result;\r
+\r
+  if (RShiftU64 (MemoryLength, 32) != 0) {\r
+    Result = LShiftU64 (\r
+               (UINT64) GetPowerOfTwo32 (\r
+                          (UINT32) RShiftU64 (MemoryLength, 32)\r
+                          ),\r
+               32\r
+               );\r
+  } else {\r
+    Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);\r
+  }\r
+\r
+  return Result;\r
+}\r
+\r
+\r
+/**\r
+  Determines the MTRR numbers used to program a memory range.\r
+\r
+  This function first checks the alignment of the base address.\r
+  If the alignment of the base address <= Length, cover the memory range\r
+ (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and\r
+  Length -= alignment. Repeat the step until alignment > Length.\r
+\r
+  Then this function determines which direction of programming the variable\r
+  MTRRs for the remaining length will use fewer MTRRs.\r
+\r
+  @param[in]  BaseAddress Length of Memory to program MTRR\r
+  @param[in]  Length      Length of Memory to program MTRR\r
+  @param[in]  MtrrNumber  Pointer to the number of necessary MTRRs\r
+\r
+  @retval TRUE        Positive direction is better.\r
+          FALSE       Negative direction is better.\r
+\r
+**/\r
+BOOLEAN\r
+GetMtrrNumberAndDirection (\r
+  IN UINT64      BaseAddress,\r
+  IN UINT64      Length,\r
+  IN UINTN       *MtrrNumber\r
+  )\r
+{\r
+  UINT64  TempQword;\r
+  UINT64  Alignment;\r
+  UINT32  Positive;\r
+  UINT32  Subtractive;\r
+\r
+  *MtrrNumber = 0;\r
+\r
+  if (BaseAddress != 0) {\r
+    do {\r
+      //\r
+      // Calculate the alignment of the base address.\r
+      //\r
+      Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
+\r
+      if (Alignment > Length) {\r
+        break;\r
+      }\r
+\r
+      (*MtrrNumber)++;\r
+      BaseAddress += Alignment;\r
+      Length -= Alignment;\r
+    } while (TRUE);\r
+\r
+    if (Length == 0) {\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  TempQword   = Length;\r
+  Positive    = 0;\r
+  Subtractive = 0;\r
+\r
+  do {\r
+    TempQword -= Power2MaxMemory (TempQword);\r
+    Positive++;\r
+  } while (TempQword != 0);\r
+\r
+  TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;\r
+  Subtractive++;\r
+  do {\r
+    TempQword -= Power2MaxMemory (TempQword);\r
+    Subtractive++;\r
+  } while (TempQword != 0);\r
+\r
+  if (Positive <= Subtractive) {\r
+    *MtrrNumber += Positive;\r
+    return TRUE;\r
+  } else {\r
+    *MtrrNumber += Subtractive;\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  Invalid variable MTRRs according to the value in the shadow array.\r
+\r
+  This function programs MTRRs according to the values specified\r
+  in the shadow array.\r
+\r
+  @param[in, out]  VariableSettings   Variable MTRR settings\r
+  @param[in]       VariableMtrrCount  Number of variable MTRRs\r
+  @param[in, out]  VariableMtrr       Shadow of variable MTRR contents\r
+\r
+**/\r
+VOID\r
+InvalidateMtrr (\r
+  IN OUT MTRR_VARIABLE_SETTINGS  *VariableSettings,\r
+  IN     UINTN                   VariableMtrrCount,\r
+  IN OUT VARIABLE_MTRR           *VariableMtrr\r
+  )\r
+{\r
+  UINTN         Index;\r
+\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+    if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {\r
+       VariableSettings->Mtrr[Index].Base = 0;\r
+       VariableSettings->Mtrr[Index].Mask = 0;\r
+       VariableMtrr[Index].Used = FALSE;\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Programs variable MTRRs\r
+\r
+  This function programs variable MTRRs\r
+\r
+  @param[in, out]  VariableSettings      Variable MTRR settings.\r
+  @param[in]       MtrrNumber            Index of MTRR to program.\r
+  @param[in]       BaseAddress           Base address of memory region.\r
+  @param[in]       Length                Length of memory region.\r
+  @param[in]       MemoryCacheType       Memory type to set.\r
+  @param[in]       MtrrValidAddressMask  The valid address mask for MTRR\r
+\r
+**/\r
+VOID\r
+ProgramVariableMtrr (\r
+  IN OUT MTRR_VARIABLE_SETTINGS  *VariableSettings,\r
+  IN     UINTN                   MtrrNumber,\r
+  IN     PHYSICAL_ADDRESS        BaseAddress,\r
+  IN     UINT64                  Length,\r
+  IN     UINT64                  MemoryCacheType,\r
+  IN     UINT64                  MtrrValidAddressMask\r
+  )\r
+{\r
+  UINT64        TempQword;\r
+\r
+  //\r
+  // MTRR Physical Base\r
+  //\r
+  TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
+  VariableSettings->Mtrr[MtrrNumber].Base = TempQword;\r
+\r
+  //\r
+  // MTRR Physical Mask\r
+  //\r
+  TempQword = ~(Length - 1);\r
+  VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED;\r
+}\r
+\r
+\r
+/**\r
+  Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.\r
+\r
+  If MtrrSetting is not NULL, gets the default memory attribute from input\r
+  MTRR settings buffer.\r
+  If MtrrSetting is NULL, gets the default memory attribute from MSR.\r
+\r
+  @param[in]  MtrrSetting        A buffer holding all MTRRs content.\r
+  @param[in]  MtrrType           MTRR memory type\r
+\r
+  @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
+\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+GetMemoryCacheTypeFromMtrrType (\r
+  IN MTRR_SETTINGS         *MtrrSetting,\r
+  IN UINT64                MtrrType\r
+  )\r
+{\r
+  switch (MtrrType) {\r
+  case MTRR_CACHE_UNCACHEABLE:\r
+    return CacheUncacheable;\r
+  case MTRR_CACHE_WRITE_COMBINING:\r
+    return CacheWriteCombining;\r
+  case MTRR_CACHE_WRITE_THROUGH:\r
+    return CacheWriteThrough;\r
+  case MTRR_CACHE_WRITE_PROTECTED:\r
+    return CacheWriteProtected;\r
+  case MTRR_CACHE_WRITE_BACK:\r
+    return CacheWriteBack;\r
+  default:\r
+    //\r
+    // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
+    // no MTRR covers the range\r
+    //\r
+    return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
+  }\r
+}\r
+\r
+/**\r
+  Initializes the valid bits mask and valid address mask for MTRRs.\r
+\r
+  This function initializes the valid bits mask and valid address mask for MTRRs.\r
+\r
+  @param[out]  MtrrValidBitsMask     The mask for the valid bit of the MTRR\r
+  @param[out]  MtrrValidAddressMask  The valid address mask for the MTRR\r
+\r
+**/\r
+VOID\r
+MtrrLibInitializeMtrrMask (\r
+  OUT UINT64 *MtrrValidBitsMask,\r
+  OUT UINT64 *MtrrValidAddressMask\r
+  )\r
+{\r
+  UINT32  RegEax;\r
+  UINT8   PhysicalAddressBits;\r
+\r
+  AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+\r
+  if (RegEax >= 0x80000008) {\r
+    AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+\r
+    PhysicalAddressBits = (UINT8) RegEax;\r
+\r
+    *MtrrValidBitsMask    = LShiftU64 (1, PhysicalAddressBits) - 1;\r
+    *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
+  } else {\r
+    *MtrrValidBitsMask    = MTRR_LIB_MSR_VALID_MASK;\r
+    *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Determines the real attribute of a memory range.\r
+\r
+  This function is to arbitrate the real attribute of the memory when\r
+  there are 2 MTRRs covers the same memory range.  For further details,\r
+  please refer the IA32 Software Developer's Manual, Volume 3,\r
+  Section 10.11.4.1.\r
+\r
+  @param[in]  MtrrType1    The first kind of Memory type\r
+  @param[in]  MtrrType2    The second kind of memory type\r
+\r
+**/\r
+UINT64\r
+MtrrPrecedence (\r
+  IN UINT64    MtrrType1,\r
+  IN UINT64    MtrrType2\r
+  )\r
+{\r
+  UINT64 MtrrType;\r
+\r
+  MtrrType = MTRR_CACHE_INVALID_TYPE;\r
+  switch (MtrrType1) {\r
+  case MTRR_CACHE_UNCACHEABLE:\r
+    MtrrType = MTRR_CACHE_UNCACHEABLE;\r
+    break;\r
+  case MTRR_CACHE_WRITE_COMBINING:\r
+    if (\r
+         MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
+         MtrrType2==MTRR_CACHE_UNCACHEABLE\r
+       ) {\r
+      MtrrType = MtrrType2;\r
+    }\r
+    break;\r
+  case MTRR_CACHE_WRITE_THROUGH:\r
+    if (\r
+         MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
+         MtrrType2==MTRR_CACHE_WRITE_BACK\r
+       ) {\r
+      MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
+    } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
+      MtrrType = MTRR_CACHE_UNCACHEABLE;\r
+    }\r
+    break;\r
+  case MTRR_CACHE_WRITE_PROTECTED:\r
+    if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
+        MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
+      MtrrType = MtrrType2;\r
+    }\r
+    break;\r
+  case MTRR_CACHE_WRITE_BACK:\r
+    if (\r
+         MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
+         MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
+         MtrrType2== MTRR_CACHE_WRITE_BACK\r
+       ) {\r
+      MtrrType = MtrrType2;\r
+    }\r
+    break;\r
+  case MTRR_CACHE_INVALID_TYPE:\r
+    MtrrType = MtrrType2;\r
+    break;\r
+  default:\r
+    break;\r
+  }\r
+\r
+  if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
+    MtrrType = MtrrType1;\r
+  }\r
+  return MtrrType;\r
+}\r
+\r
+/**\r
+  Worker function will get the memory cache type of the specific address.\r
+\r
+  If MtrrSetting is not NULL, gets the memory cache type from input\r
+  MTRR settings buffer.\r
+  If MtrrSetting is NULL, gets the memory cache type from MTRRs.\r
+\r
+  @param[in]  MtrrSetting        A buffer holding all MTRRs content.\r
+  @param[in]  Address            The specific address\r
+\r
+  @return Memory cache type of the specific address\r
+\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+MtrrGetMemoryAttributeByAddressWorker (\r
+  IN MTRR_SETTINGS      *MtrrSetting,\r
+  IN PHYSICAL_ADDRESS   Address\r
+  )\r
+{\r
+  UINT64                  TempQword;\r
+  UINTN                   Index;\r
+  UINTN                   SubIndex;\r
+  UINT64                  MtrrType;\r
+  UINT64                  TempMtrrType;\r
+  MTRR_MEMORY_CACHE_TYPE  CacheType;\r
+  VARIABLE_MTRR           VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+  UINT64                  MtrrValidBitsMask;\r
+  UINT64                  MtrrValidAddressMask;\r
+  UINTN                   VariableMtrrCount;\r
+  MTRR_VARIABLE_SETTINGS  VariableSettings;\r
+\r
+  //\r
+  // Check if MTRR is enabled, if not, return UC as attribute\r
+  //\r
+  if (MtrrSetting == NULL) {\r
+    TempQword = MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE);\r
+  } else {\r
+    TempQword = MtrrSetting->MtrrDefType;\r
+  }\r
+  MtrrType = MTRR_CACHE_INVALID_TYPE;\r
+\r
+  if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+    return CacheUncacheable;\r
+  }\r
+\r
+  //\r
+  // If address is less than 1M, then try to go through the fixed MTRR\r
+  //\r
+  if (Address < BASE_1MB) {\r
+    if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
+      //\r
+      // Go through the fixed MTRR\r
+      //\r
+      for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+         if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
+             Address  < (\r
+                          mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
+                          (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
+                        )\r
+            ) {\r
+           SubIndex =\r
+             ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
+               mMtrrLibFixedMtrrTable[Index].Length;\r
+           if (MtrrSetting == NULL) {\r
+             TempQword = MtrrRegisterRead (mMtrrLibFixedMtrrTable[Index].Msr);\r
+           } else {\r
+             TempQword = MtrrSetting->Fixed.Mtrr[Index];\r
+           }\r
+           MtrrType =  RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
+           return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
+         }\r
+      }\r
+    }\r
+  }\r
+  MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
+\r
+  MtrrGetVariableMtrrWorker (\r
+    MtrrSetting,\r
+    GetVariableMtrrCountWorker (),\r
+    &VariableSettings\r
+    );\r
+\r
+  MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+           &VariableSettings,\r
+           GetFirmwareVariableMtrrCountWorker (),\r
+           MtrrValidBitsMask,\r
+           MtrrValidAddressMask,\r
+           VariableMtrr\r
+           );\r
+\r
+  //\r
+  // Go through the variable MTRR\r
+  //\r
+  VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+    if (VariableMtrr[Index].Valid) {\r
+      if (Address >= VariableMtrr[Index].BaseAddress &&\r
+          Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
+        TempMtrrType = VariableMtrr[Index].Type;\r
+        MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);\r
+      }\r
+    }\r
+  }\r
+  CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
+\r
+  return CacheType;\r
+}\r
+\r
+\r
+/**\r
+  This function will get the memory cache type of the specific address.\r
+\r
+  This function is mainly for debug purpose.\r
+\r
+  @param[in]  Address   The specific address\r
+\r
+  @return Memory cache type of the specific address\r
+\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+EFIAPI\r
+MtrrGetMemoryAttribute (\r
+  IN PHYSICAL_ADDRESS   Address\r
+  )\r
+{\r
+  if (!IsMtrrSupported ()) {\r
+    return CacheUncacheable;\r
+  }\r
+\r
+  return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);\r
+}\r
+\r
+/**\r
+  Worker function prints all MTRRs for debugging.\r
+\r
+  If MtrrSetting is not NULL, print MTRR settings from from input MTRR\r
+  settings buffer.\r
+  If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
+\r
+  @param  MtrrSetting    A buffer holding all MTRRs content.\r
+**/\r
+VOID\r
+MtrrDebugPrintAllMtrrsWorker (\r
+  IN MTRR_SETTINGS    *MtrrSetting\r
+  )\r
+{\r
+  DEBUG_CODE (\r
+    MTRR_SETTINGS  LocalMtrrs;\r
+    MTRR_SETTINGS  *Mtrrs;\r
+    UINTN          Index;\r
+    UINTN          Index1;\r
+    UINTN          VariableMtrrCount;\r
+    UINT64         Base;\r
+    UINT64         Limit;\r
+    UINT64         MtrrBase;\r
+    UINT64         MtrrLimit;\r
+    UINT64         RangeBase;\r
+    UINT64         RangeLimit;\r
+    UINT64         NoRangeBase;\r
+    UINT64         NoRangeLimit;\r
+    UINT32         RegEax;\r
+    UINTN          MemoryType;\r
+    UINTN          PreviousMemoryType;\r
+    BOOLEAN        Found;\r
+\r
+    if (!IsMtrrSupported ()) {\r
+      return;\r
+    }\r
+\r
+    DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
+    DEBUG((DEBUG_CACHE, "=============\n"));\r
+\r
+    if (MtrrSetting != NULL) {\r
+      Mtrrs = MtrrSetting;\r
+    } else {\r
+      MtrrGetAllMtrrs (&LocalMtrrs);\r
+      Mtrrs = &LocalMtrrs;\r
+    }\r
+\r
+    DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
+    for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+      DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d]   : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
+    }\r
+\r
+    VariableMtrrCount = GetVariableMtrrCount ();\r
+    for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+      DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
+        Index,\r
+        Mtrrs->Variables.Mtrr[Index].Base,\r
+        Mtrrs->Variables.Mtrr[Index].Mask\r
+        ));\r
+    }\r
+    DEBUG((DEBUG_CACHE, "\n"));\r
+    DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
+    DEBUG((DEBUG_CACHE, "====================================\n"));\r
+\r
+    Base = 0;\r
+    PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
+    for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+      Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
+      for (Index1 = 0; Index1 < 8; Index1++) {\r
+      MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
+        if (MemoryType > CacheWriteBack) {\r
+          MemoryType = MTRR_CACHE_INVALID_TYPE;\r
+        }\r
+        if (MemoryType != PreviousMemoryType) {\r
+          if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
+            DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
+          }\r
+          PreviousMemoryType = MemoryType;\r
+          DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
+        }\r
+        Base += mMtrrLibFixedMtrrTable[Index].Length;\r
+      }\r
+    }\r
+    DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
+\r
+    VariableMtrrCount = GetVariableMtrrCount ();\r
+\r
+    Limit        = BIT36 - 1;\r
+    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+    if (RegEax >= 0x80000008) {\r
+      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+      Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
+    }\r
+    Base = BASE_1MB;\r
+    PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
+    do {\r
+      MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);\r
+      if (MemoryType > CacheWriteBack) {\r
+        MemoryType = MTRR_CACHE_INVALID_TYPE;\r
+      }\r
+\r
+      if (MemoryType != PreviousMemoryType) {\r
+        if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
+          DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
+        }\r
+        PreviousMemoryType = MemoryType;\r
+        DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
+      }\r
+\r
+      RangeBase    = BASE_1MB;\r
+      NoRangeBase  = BASE_1MB;\r
+      RangeLimit   = Limit;\r
+      NoRangeLimit = Limit;\r
+\r
+      for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
+        if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
+          //\r
+          // If mask is not valid, then do not display range\r
+          //\r
+          continue;\r
+        }\r
+        MtrrBase  = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
+        MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
+\r
+        if (Base >= MtrrBase && Base < MtrrLimit) {\r
+          Found = TRUE;\r
+        }\r
+\r
+        if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
+          RangeBase = MtrrBase;\r
+        }\r
+        if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
+          RangeBase = MtrrLimit + 1;\r
+        }\r
+        if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
+          RangeLimit = MtrrBase - 1;\r
+        }\r
+        if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
+          RangeLimit = MtrrLimit;\r
+        }\r
+\r
+        if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
+          NoRangeBase = MtrrLimit + 1;\r
+        }\r
+        if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
+          NoRangeLimit = MtrrBase - 1;\r
+        }\r
+      }\r
+\r
+      if (Found) {\r
+        Base = RangeLimit + 1;\r
+      } else {\r
+        Base = NoRangeLimit + 1;\r
+      }\r
+    } while (Base < Limit);\r
+    DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
+  );\r
+}\r
+\r
+\r
+/**\r
+  This function prints all MTRRs for debugging.\r
+**/\r
+VOID\r
+EFIAPI\r
+MtrrDebugPrintAllMtrrs (\r
+  VOID\r
+  )\r
+{\r
+  MtrrDebugPrintAllMtrrsWorker (NULL);\r
+}\r
+\r
+\r
+/**\r
+  Worker function attempts to set the attributes for a memory range.\r
+\r
+  If MtrrSettings is not NULL, set the attributes into the input MTRR\r
+  settings buffer.\r
+  If MtrrSettings is NULL, set the attributes into MTRRs registers.\r
+\r
+  @param[in, out]  MtrrSetting       A buffer holding all MTRRs content.\r
+  @param[in]       BaseAddress       The physical address that is the start\r
+                                     address of a memory region.\r
+  @param[in]       Length            The size in bytes of the memory region.\r
+  @param[in]       Attribute         The bit mask of attributes to set for the\r
+                                     memory region.\r
+\r
+  @retval RETURN_SUCCESS            The attributes were set for the memory\r
+                                    region.\r
+  @retval RETURN_INVALID_PARAMETER  Length is zero.\r
+  @retval RETURN_UNSUPPORTED        The processor does not support one or\r
+                                    more bytes of the memory resource range\r
+                                    specified by BaseAddress and Length.\r
+  @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support\r
+                                    for the memory resource range specified\r
+                                    by BaseAddress and Length.\r
+  @retval RETURN_ACCESS_DENIED      The attributes for the memory resource\r
+                                    range specified by BaseAddress and Length\r
+                                    cannot be modified.\r
+  @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to\r
+                                    modify the attributes of the memory\r
+                                    resource range.\r
+\r
+**/\r
+RETURN_STATUS\r
+MtrrSetMemoryAttributeWorker (\r
+  IN OUT MTRR_SETTINGS           *MtrrSetting,\r
+  IN PHYSICAL_ADDRESS            BaseAddress,\r
+  IN UINT64                      Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE      Attribute\r
+  )\r
+{\r
+  UINT64                    TempQword;\r
+  RETURN_STATUS             Status;\r
+  UINT64                    MemoryType;\r
+  UINT64                    Alignment;\r
+  BOOLEAN                   OverLap;\r
+  BOOLEAN                   Positive;\r
+  UINT32                    MsrNum;\r
+  UINTN                     MtrrNumber;\r
+  VARIABLE_MTRR             VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+  UINT32                    UsedMtrr;\r
+  UINT64                    MtrrValidBitsMask;\r
+  UINT64                    MtrrValidAddressMask;\r
+  BOOLEAN                   OverwriteExistingMtrr;\r
+  UINT32                    FirmwareVariableMtrrCount;\r
+  MTRR_CONTEXT              MtrrContext;\r
+  BOOLEAN                   MtrrContextValid;\r
+  BOOLEAN                   FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
+  BOOLEAN                   FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
+  MTRR_FIXED_SETTINGS       WorkingFixedSettings;\r
+  UINT32                    VariableMtrrCount;\r
+  MTRR_VARIABLE_SETTINGS    OriginalVariableSettings;\r
+  BOOLEAN                   ProgramVariableSettings;\r
+  MTRR_VARIABLE_SETTINGS    WorkingVariableSettings;\r
+  UINT32                    Index;\r
+  UINT64                    ClearMask;\r
+  UINT64                    OrMask;\r
+  UINT64                    NewValue;\r
+  MTRR_VARIABLE_SETTINGS    *VariableSettings;\r
+\r
+  MtrrContextValid  = FALSE;\r
+  VariableMtrrCount = 0;\r
+  ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+    FixedSettingsValid[Index]    = FALSE;\r
+    FixedSettingsModified[Index] = FALSE;\r
+  }\r
+  ProgramVariableSettings = FALSE;\r
+\r
+  if (!IsMtrrSupported ()) {\r
+    Status = RETURN_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+\r
+  MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
+\r
+  TempQword = 0;\r
+  MemoryType = (UINT64)Attribute;\r
+  OverwriteExistingMtrr = FALSE;\r
+\r
+  //\r
+  // Check for an invalid parameter\r
+  //\r
+  if (Length == 0) {\r
+    Status = RETURN_INVALID_PARAMETER;\r
+    goto Done;\r
+  }\r
+\r
+  if (\r
+       (BaseAddress & ~MtrrValidAddressMask) != 0 ||\r
+       (Length & ~MtrrValidAddressMask) != 0\r
+     ) {\r
+    Status = RETURN_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Check if Fixed MTRR\r
+  //\r
+  Status = RETURN_SUCCESS;\r
+  if (BaseAddress < BASE_1MB) {\r
+    while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
+      Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);\r
+      if (RETURN_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
+      if (MtrrSetting != NULL) {\r
+        MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
+        MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED;\r
+      } else {\r
+        if (!FixedSettingsValid[MsrNum]) {\r
+          WorkingFixedSettings.Mtrr[MsrNum] = MtrrRegisterRead (mMtrrLibFixedMtrrTable[MsrNum].Msr);\r
+          FixedSettingsValid[MsrNum] = TRUE;\r
+        }\r
+        NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
+        if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {\r
+          WorkingFixedSettings.Mtrr[MsrNum] = NewValue;\r
+          FixedSettingsModified[MsrNum] = TRUE;\r
+        }\r
+      }\r
+    }\r
+\r
+    if (Length == 0) {\r
+      //\r
+      // A Length of 0 can only make sense for fixed MTTR ranges.\r
+      // Since we just handled the fixed MTRRs, we can skip the\r
+      // variable MTRR section.\r
+      //\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
+  // we can set the base to 0 to save variable MTRRs.\r
+  //\r
+  if (BaseAddress == BASE_1MB) {\r
+    BaseAddress = 0;\r
+    Length += SIZE_1MB;\r
+  }\r
+\r
+  //\r
+  // Read all variable MTRRs\r
+  //\r
+  VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+  FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
+  if (MtrrSetting != NULL) {\r
+    VariableSettings = &MtrrSetting->Variables;\r
+  } else {\r
+    MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings);\r
+    CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));\r
+    ProgramVariableSettings = TRUE;\r
+    VariableSettings = &WorkingVariableSettings;\r
+  }\r
+\r
+  //\r
+  // Check for overlap\r
+  //\r
+  UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+               VariableSettings,\r
+               FirmwareVariableMtrrCount,\r
+               MtrrValidBitsMask,\r
+               MtrrValidAddressMask,\r
+               VariableMtrr\r
+               );\r
+  OverLap = CheckMemoryAttributeOverlap (\r
+              FirmwareVariableMtrrCount,\r
+              BaseAddress,\r
+              BaseAddress + Length - 1,\r
+              VariableMtrr\r
+              );\r
+  if (OverLap) {\r
+    Status = CombineMemoryAttribute (\r
+               FirmwareVariableMtrrCount,\r
+               MemoryType,\r
+               &BaseAddress,\r
+               &Length,\r
+               VariableMtrr,\r
+               &UsedMtrr,\r
+               &OverwriteExistingMtrr\r
+               );\r
+    if (RETURN_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    if (Length == 0) {\r
+      //\r
+      // Combined successfully, invalidate the now-unused MTRRs\r
+      //\r
+      InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
+      Status = RETURN_SUCCESS;\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  //\r
+  // The memory type is the same with the type specified by\r
+  // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
+  //\r
+  if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) {\r
+    //\r
+    // Invalidate the now-unused MTRRs\r
+    //\r
+    InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
+    goto Done;\r
+  }\r
+\r
+  Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);\r
+\r
+  if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
+    Status = RETURN_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Invalidate the now-unused MTRRs\r
+  //\r
+  InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
+\r
+  //\r
+  // Find first unused MTRR\r
+  //\r
+  for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {\r
+    if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (BaseAddress != 0) {\r
+    do {\r
+      //\r
+      // Calculate the alignment of the base address.\r
+      //\r
+      Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
+\r
+      if (Alignment > Length) {\r
+        break;\r
+      }\r
+\r
+      //\r
+      // Find unused MTRR\r
+      //\r
+      for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
+        if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+          break;\r
+        }\r
+      }\r
+\r
+      ProgramVariableMtrr (\r
+        VariableSettings,\r
+        MsrNum,\r
+        BaseAddress,\r
+        Alignment,\r
+        MemoryType,\r
+        MtrrValidAddressMask\r
+        );\r
+      BaseAddress += Alignment;\r
+      Length -= Alignment;\r
+    } while (TRUE);\r
+\r
+    if (Length == 0) {\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  TempQword = Length;\r
+\r
+  if (!Positive) {\r
+    Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
+\r
+    //\r
+    // Find unused MTRR\r
+    //\r
+    for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
+      if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    ProgramVariableMtrr (\r
+      VariableSettings,\r
+      MsrNum,\r
+      BaseAddress,\r
+      Length,\r
+      MemoryType,\r
+      MtrrValidAddressMask\r
+      );\r
+    BaseAddress += Length;\r
+    TempQword   = Length - TempQword;\r
+    MemoryType  = MTRR_CACHE_UNCACHEABLE;\r
+  }\r
+\r
+  do {\r
+    //\r
+    // Find unused MTRR\r
+    //\r
+    for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
+      if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    Length = Power2MaxMemory (TempQword);\r
+    if (!Positive) {\r
+      BaseAddress -= Length;\r
+    }\r
+\r
+    ProgramVariableMtrr (\r
+      VariableSettings,\r
+      MsrNum,\r
+      BaseAddress,\r
+      Length,\r
+      MemoryType,\r
+      MtrrValidAddressMask\r
+      );\r
+\r
+    if (Positive) {\r
+      BaseAddress += Length;\r
+    }\r
+    TempQword -= Length;\r
+\r
+  } while (TempQword > 0);\r
+\r
+Done:\r
+\r
+  //\r
+  // Write fixed MTRRs that have been modified\r
+  //\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+    if (FixedSettingsModified[Index]) {\r
+      if (!MtrrContextValid) {\r
+        PreMtrrChange (&MtrrContext);\r
+        MtrrContextValid = TRUE;\r
+      }\r
+      MtrrRegisterWrite (\r
+        mMtrrLibFixedMtrrTable[Index].Msr,\r
+        WorkingFixedSettings.Mtrr[Index]\r
+        );\r
+    }\r
+  }\r
+\r
+  //\r
+  // Write variable MTRRs\r
+  //\r
+  if (ProgramVariableSettings) {\r
+    for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+      if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||\r
+          WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask    ) {\r
+        if (!MtrrContextValid) {\r
+          PreMtrrChange (&MtrrContext);\r
+          MtrrContextValid = TRUE;\r
+        }\r
+        MtrrRegisterWrite (\r
+          QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
+          WorkingVariableSettings.Mtrr[Index].Base\r
+          );\r
+        MtrrRegisterWrite (\r
+          QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1,\r
+          WorkingVariableSettings.Mtrr[Index].Mask\r
+          );\r
+      }\r
+    }\r
+  }\r
+  if (MtrrContextValid) {\r
+    PostMtrrChange (&MtrrContext);\r
+  }\r
+\r
+  DEBUG((DEBUG_CACHE, "  Status = %r\n", Status));\r
+  if (!RETURN_ERROR (Status)) {\r
+    if (MtrrSetting != NULL) {\r
+      MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED;\r
+    }\r
+    MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function attempts to set the attributes for a memory range.\r
+\r
+  @param[in]  BaseAddress        The physical address that is the start\r
+                                 address of a memory region.\r
+  @param[in]  Length             The size in bytes of the memory region.\r
+  @param[in]  Attributes         The bit mask of attributes to set for the\r
+                                 memory region.\r
+\r
+  @retval RETURN_SUCCESS            The attributes were set for the memory\r
+                                    region.\r
+  @retval RETURN_INVALID_PARAMETER  Length is zero.\r
+  @retval RETURN_UNSUPPORTED        The processor does not support one or\r
+                                    more bytes of the memory resource range\r
+                                    specified by BaseAddress and Length.\r
+  @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support\r
+                                    for the memory resource range specified\r
+                                    by BaseAddress and Length.\r
+  @retval RETURN_ACCESS_DENIED      The attributes for the memory resource\r
+                                    range specified by BaseAddress and Length\r
+                                    cannot be modified.\r
+  @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to\r
+                                    modify the attributes of the memory\r
+                                    resource range.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+MtrrSetMemoryAttribute (\r
+  IN PHYSICAL_ADDRESS        BaseAddress,\r
+  IN UINT64                  Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
+  )\r
+{\r
+  DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
+  return MtrrSetMemoryAttributeWorker (\r
+           NULL,\r
+           BaseAddress,\r
+           Length,\r
+           Attribute\r
+           );\r
+}\r
+\r
+/**\r
+  This function attempts to set the attributes into MTRR setting buffer for a memory range.\r
+\r
+  @param[in, out]  MtrrSetting  MTRR setting buffer to be set.\r
+  @param[in]       BaseAddress  The physical address that is the start address\r
+                                of a memory region.\r
+  @param[in]       Length       The size in bytes of the memory region.\r
+  @param[in]       Attribute    The bit mask of attributes to set for the\r
+                                memory region.\r
+\r
+  @retval RETURN_SUCCESS            The attributes were set for the memory region.\r
+  @retval RETURN_INVALID_PARAMETER  Length is zero.\r
+  @retval RETURN_UNSUPPORTED        The processor does not support one or more bytes of the\r
+                                    memory resource range specified by BaseAddress and Length.\r
+  @retval RETURN_UNSUPPORTED        The bit mask of attributes is not support for the memory resource\r
+                                    range specified by BaseAddress and Length.\r
+  @retval RETURN_ACCESS_DENIED      The attributes for the memory resource range specified by\r
+                                    BaseAddress and Length cannot be modified.\r
+  @retval RETURN_OUT_OF_RESOURCES   There are not enough system resources to modify the attributes of\r
+                                    the memory resource range.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+MtrrSetMemoryAttributeInMtrrSettings (\r
+  IN OUT MTRR_SETTINGS       *MtrrSetting,\r
+  IN PHYSICAL_ADDRESS        BaseAddress,\r
+  IN UINT64                  Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
+  )\r
+{\r
+  DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
+  return MtrrSetMemoryAttributeWorker (\r
+           MtrrSetting,\r
+           BaseAddress,\r
+           Length,\r
+           Attribute\r
+           );\r
+}\r
+\r
+/**\r
+  Worker function setting variable MTRRs\r
+\r
+  @param[in]  VariableSettings   A buffer to hold variable MTRRs content.\r
+\r
+**/\r
+VOID\r
+MtrrSetVariableMtrrWorker (\r
+  IN MTRR_VARIABLE_SETTINGS         *VariableSettings\r
+  )\r
+{\r
+  UINT32  Index;\r
+  UINT32  VariableMtrrCount;\r
+\r
+  VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+  ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+    MtrrRegisterWrite (\r
+      QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
+      VariableSettings->Mtrr[Index].Base\r
+      );\r
+    MtrrRegisterWrite (\r
+      QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1,\r
+      VariableSettings->Mtrr[Index].Mask\r
+      );\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This function sets variable MTRRs\r
+\r
+  @param[in]  VariableSettings   A buffer to hold variable MTRRs content.\r
+\r
+  @return The pointer of VariableSettings\r
+\r
+**/\r
+MTRR_VARIABLE_SETTINGS*\r
+EFIAPI\r
+MtrrSetVariableMtrr (\r
+  IN MTRR_VARIABLE_SETTINGS         *VariableSettings\r
+  )\r
+{\r
+  MTRR_CONTEXT  MtrrContext;\r
+\r
+  if (!IsMtrrSupported ()) {\r
+    return VariableSettings;\r
+  }\r
+\r
+  PreMtrrChange (&MtrrContext);\r
+  MtrrSetVariableMtrrWorker (VariableSettings);\r
+  PostMtrrChange (&MtrrContext);\r
+  MtrrDebugPrintAllMtrrs ();\r
+\r
+  return  VariableSettings;\r
+}\r
+\r
+/**\r
+  Worker function setting fixed MTRRs\r
+\r
+  @param[in]  FixedSettings  A buffer to hold fixed MTRRs content.\r
+\r
+**/\r
+VOID\r
+MtrrSetFixedMtrrWorker (\r
+  IN MTRR_FIXED_SETTINGS          *FixedSettings\r
+  )\r
+{\r
+  UINT32  Index;\r
+\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+     MtrrRegisterWrite (\r
+       mMtrrLibFixedMtrrTable[Index].Msr,\r
+       FixedSettings->Mtrr[Index]\r
+       );\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This function sets fixed MTRRs\r
+\r
+  @param[in]  FixedSettings  A buffer to hold fixed MTRRs content.\r
+\r
+  @retval The pointer of FixedSettings\r
+\r
+**/\r
+MTRR_FIXED_SETTINGS*\r
+EFIAPI\r
+MtrrSetFixedMtrr (\r
+  IN MTRR_FIXED_SETTINGS          *FixedSettings\r
+  )\r
+{\r
+  MTRR_CONTEXT  MtrrContext;\r
+\r
+  if (!IsMtrrSupported ()) {\r
+    return FixedSettings;\r
+  }\r
+\r
+  PreMtrrChange (&MtrrContext);\r
+  MtrrSetFixedMtrrWorker (FixedSettings);\r
+  PostMtrrChange (&MtrrContext);\r
+  MtrrDebugPrintAllMtrrs ();\r
+\r
+  return FixedSettings;\r
+}\r
+\r
+\r
+/**\r
+  This function gets the content in all MTRRs (variable and fixed)\r
+\r
+  @param[out]  MtrrSetting  A buffer to hold all MTRRs content.\r
+\r
+  @retval the pointer of MtrrSetting\r
+\r
+**/\r
+MTRR_SETTINGS *\r
+EFIAPI\r
+MtrrGetAllMtrrs (\r
+  OUT MTRR_SETTINGS                *MtrrSetting\r
+  )\r
+{\r
+  if (!IsMtrrSupported ()) {\r
+    return MtrrSetting;\r
+  }\r
+\r
+  //\r
+  // Get fixed MTRRs\r
+  //\r
+  MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);\r
+\r
+  //\r
+  // Get variable MTRRs\r
+  //\r
+  MtrrGetVariableMtrrWorker (\r
+    NULL,\r
+    GetVariableMtrrCountWorker (),\r
+    &MtrrSetting->Variables\r
+    );\r
+\r
+  //\r
+  // Get MTRR_DEF_TYPE value\r
+  //\r
+  MtrrSetting->MtrrDefType = MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE);\r
+\r
+  return MtrrSetting;\r
+}\r
+\r
+\r
+/**\r
+  This function sets all MTRRs (variable and fixed)\r
+\r
+  @param[in]  MtrrSetting  A buffer holding all MTRRs content.\r
+\r
+  @retval The pointer of MtrrSetting\r
+\r
+**/\r
+MTRR_SETTINGS *\r
+EFIAPI\r
+MtrrSetAllMtrrs (\r
+  IN MTRR_SETTINGS                *MtrrSetting\r
+  )\r
+{\r
+  MTRR_CONTEXT  MtrrContext;\r
+\r
+  if (!IsMtrrSupported ()) {\r
+    return MtrrSetting;\r
+  }\r
+\r
+  PreMtrrChange (&MtrrContext);\r
+\r
+  //\r
+  // Set fixed MTRRs\r
+  //\r
+  MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
+\r
+  //\r
+  // Set variable MTRRs\r
+  //\r
+  MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
+\r
+  //\r
+  // Set MTRR_DEF_TYPE value\r
+  //\r
+  MtrrRegisterWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
+\r
+  PostMtrrChangeEnableCache (&MtrrContext);\r
+\r
+  MtrrDebugPrintAllMtrrs ();\r
+\r
+  return MtrrSetting;\r
+}\r
+\r
+\r
+/**\r
+  Checks if MTRR is supported.\r
+\r
+  @retval TRUE  MTRR is supported.\r
+  @retval FALSE MTRR is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsMtrrSupported (\r
+  VOID\r
+  )\r
+{\r
+  UINT32  RegEax;\r
+\r
+  //\r
+  // Check CPUID(1).EAX[0..11] for Quark SoC\r
+  //\r
+  AsmCpuid (1, &RegEax, NULL, NULL, NULL);\r
+  if ((RegEax & 0xfff) == QUARK_SOC_CPUID_FAMILY_MODEL_STEPPING) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r