Add MTRR library for IA32 & X64 processor architectures.
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 27 May 2009 21:09:39 +0000 (21:09 +0000)
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 27 May 2009 21:09:39 +0000 (21:09 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@8394 6f19259b-4bc3-4df7-8a09-765794883524

UefiCpuPkg/Include/Library/MtrrLib.h [new file with mode: 0644]
UefiCpuPkg/Library/MtrrLib/MtrrLib.c [new file with mode: 0644]
UefiCpuPkg/Library/MtrrLib/MtrrLib.inf [new file with mode: 0644]
UefiCpuPkg/UefiCpuPkg.dec

diff --git a/UefiCpuPkg/Include/Library/MtrrLib.h b/UefiCpuPkg/Include/Library/MtrrLib.h
new file mode 100644 (file)
index 0000000..c81c49b
--- /dev/null
@@ -0,0 +1,288 @@
+/** @file\r
+  MTRR setting library\r
+\r
+  Copyright (c) 2008 - 2009, Intel Corporation\r
+  All rights reserved. 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
+#ifndef  _MTRR_LIB_H_\r
+#define  _MTRR_LIB_H_\r
+\r
+//\r
+// According to IA32 SDM, MTRRs number and msr offset are always consistent\r
+// for IA32 processor family\r
+//\r
+#define  MTRR_NUMBER_OF_VARIABLE_MTRR   8\r
+#define  MTRR_NUMBER_OF_FIXED_MTRR      11\r
+#define  FIRMWARE_VARIABLE_MTRR_NUMBER  6\r
+#define  MTRR_LIB_IA32_MTRR_FIX64K_00000             0x250\r
+#define  MTRR_LIB_IA32_MTRR_FIX16K_80000             0x258\r
+#define  MTRR_LIB_IA32_MTRR_FIX16K_A0000             0x259\r
+#define  MTRR_LIB_IA32_MTRR_FIX4K_C0000              0x268\r
+#define  MTRR_LIB_IA32_MTRR_FIX4K_C8000              0x269\r
+#define  MTRR_LIB_IA32_MTRR_FIX4K_D0000              0x26A\r
+#define  MTRR_LIB_IA32_MTRR_FIX4K_D8000              0x26B\r
+#define  MTRR_LIB_IA32_MTRR_FIX4K_E0000              0x26C\r
+#define  MTRR_LIB_IA32_MTRR_FIX4K_E8000              0x26D\r
+#define  MTRR_LIB_IA32_MTRR_FIX4K_F0000              0x26E\r
+#define  MTRR_LIB_IA32_MTRR_FIX4K_F8000              0x26F\r
+#define  MTRR_LIB_IA32_VARIABLE_MTRR_BASE            0x200\r
+#define  MTRR_LIB_IA32_VARIABLE_MTRR_END             0x20F\r
+#define  MTRR_LIB_IA32_MTRR_DEF_TYPE                 0x2FF\r
+#define  MTRR_LIB_MSR_VALID_MASK                     0xFFFFFFFFFULL\r
+#define  MTRR_LIB_CACHE_VALID_ADDRESS                0xFFFFFF000ULL\r
+#define  MTRR_LIB_CACHE_MTRR_ENABLED                 0x800\r
+#define  MTRR_LIB_CACHE_FIXED_MTRR_ENABLED           0x400\r
+\r
+//\r
+// Structure to describe a fixed MTRR\r
+//\r
+typedef struct {\r
+  UINT32  Msr;\r
+  UINT32  BaseAddress;\r
+  UINT32  Length;\r
+} FIXED_MTRR;\r
+\r
+//\r
+// Structure to describe a variable MTRR\r
+//\r
+typedef struct {\r
+  UINT64  BaseAddress;\r
+  UINT64  Length;\r
+  UINT64  Type;\r
+  UINT32  Msr;\r
+  BOOLEAN Valid;\r
+  BOOLEAN Used;\r
+} VARIABLE_MTRR;\r
+\r
+//\r
+// Structure to hold base and mask pair for variable MTRR register\r
+//\r
+typedef struct _MTRR_VARIABLE_SETTING_ {\r
+       UINT64    Base;\r
+       UINT64    Mask;\r
+} MTRR_VARIABLE_SETTING;\r
+\r
+//\r
+// Array for variable MTRRs\r
+//\r
+typedef struct _MTRR_VARIABLE_SETTINGS_ {\r
+       MTRR_VARIABLE_SETTING   Mtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+}      MTRR_VARIABLE_SETTINGS;\r
+\r
+//\r
+// Array for fixed mtrrs\r
+//\r
+typedef  struct  _MTRR_FIXED_SETTINGS_ {\r
+  UINT64       Mtrr[MTRR_NUMBER_OF_FIXED_MTRR];\r
+} MTRR_FIXED_SETTINGS;\r
+\r
+//\r
+// Structure to hold all MTRRs\r
+//\r
+typedef struct _MTRR_SETTINGS_ {\r
+  MTRR_FIXED_SETTINGS       Fixed;\r
+  MTRR_VARIABLE_SETTINGS    Variables;\r
+  UINT64                    MtrrDefType;\r
+} MTRR_SETTINGS;\r
+\r
+//\r
+// Memory cache types\r
+//\r
+typedef enum {\r
+       CacheUncacheable    = 0,\r
+       CacheWriteCombining = 1,\r
+       CacheWriteThrough   = 4,\r
+       CacheWriteProtected = 5,\r
+       CacheWriteBack      = 6\r
+} MTRR_MEMORY_CACHE_TYPE;\r
+\r
+#define  MTRR_CACHE_UNCACHEABLE      0\r
+#define  MTRR_CACHE_WRITE_COMBINING  1\r
+#define  MTRR_CACHE_WRITE_THROUGH    4\r
+#define  MTRR_CACHE_WRITE_PROTECTED  5\r
+#define  MTRR_CACHE_WRITE_BACK       6\r
+#define  MTRR_CACHE_INVALID_TYPE     7\r
+\r
+//\r
+// structure for memory attribute descriptor according MTRR setting\r
+//\r
+typedef struct _MTRR_MEMORY_ATTRIBUTE_MAP_ {\r
+       PHYSICAL_ADDRESS       StartAddress;\r
+       PHYSICAL_ADDRESS       EndAddress;\r
+       MTRR_MEMORY_CACHE_TYPE Attribute;\r
+} MTRR_MEMORY_ATTRIBUTE_MAP;\r
+\r
+\r
+/**\r
+  This function attempts to set the attributes for a memory range.\r
+\r
+  @param  BaseAddress            The physical address that is the start address of a memory region.\r
+  @param  Length                 The size in bytes of the memory region.\r
+  @param  Attributes             The bit mask of attributes to set for the 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
+MtrrSetMemoryAttribute (\r
+  IN PHYSICAL_ADDRESS        BaseAddress,\r
+  IN UINT64                  Length,\r
+  IN MTRR_MEMORY_CACHE_TYPE  Attribute\r
+  );\r
+\r
+\r
+/**\r
+  This function will get the memory cache type of the specific address.\r
+  This function is mainly for debugging purposes.\r
+\r
+  @param  Address            The specific address\r
+\r
+  @return The 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
+\r
+/**\r
+  This function will get the raw value in variable MTRRs\r
+\r
+  @param  VariableSettings   A buffer to hold variable MTRRs content.\r
+\r
+  @return The buffer point to MTRR_VARIABLE_SETTINGS in which holds the content of the variable mtrr\r
+\r
+**/\r
+MTRR_VARIABLE_SETTINGS*\r
+EFIAPI\r
+MtrrGetVariableMtrr (\r
+  OUT MTRR_VARIABLE_SETTINGS         *VariableSettings\r
+  );\r
+\r
+\r
+/**\r
+  This function sets fixed MTRRs\r
+\r
+  @param  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
+\r
+/**\r
+  This function gets the content in fixed MTRRs\r
+\r
+  @param  FixedSettings      A buffer to hold fixed MTRRs content.\r
+\r
+  @return The pointer of FixedSettings\r
+\r
+**/\r
+MTRR_FIXED_SETTINGS*\r
+EFIAPI\r
+MtrrGetFixedMtrr (\r
+  OUT MTRR_FIXED_SETTINGS         *FixedSettings\r
+  );\r
+\r
+\r
+/**\r
+  This function sets fixed MTRRs\r
+\r
+  @param   FixedSettings      A buffer holding fixed MTRRs content.\r
+\r
+  @return  The pointer of FixedSettings\r
+\r
+**/\r
+MTRR_FIXED_SETTINGS*\r
+EFIAPI\r
+MtrrSetFixedMtrr (\r
+  IN MTRR_FIXED_SETTINGS          *FixedSettings\r
+  );\r
+\r
+\r
+/**\r
+  This function gets the content in all MTRRs (variable and fixed)\r
+\r
+  @param  MtrrSetting   A buffer to hold all MTRRs content.\r
+\r
+  @return The pointer of MtrrSetting\r
+\r
+**/\r
+MTRR_SETTINGS *\r
+EFIAPI\r
+MtrrGetAllMtrrs (\r
+  OUT MTRR_SETTINGS                *MtrrSetting\r
+  );\r
+\r
+\r
+/**\r
+  This function sets all MTRRs (variable and fixed)\r
+\r
+  @param  MtrrSetting   A buffer to hold all MTRRs content.\r
+\r
+  @return The pointer of MtrrSetting\r
+\r
+**/\r
+MTRR_SETTINGS *\r
+EFIAPI\r
+MtrrSetAllMtrrs (\r
+  IN MTRR_SETTINGS                *MtrrSetting\r
+  );\r
+\r
+\r
+/**\r
+  Get the attribute of variable MTRRs.\r
+\r
+  This function shadows the content of variable MTRRs into\r
+  an internal array: VariableMtrr\r
+\r
+  @param  MtrrValidBitsMask     The mask for the valid bit of the MTRR\r
+  @param  MtrrValidAddressMask  The valid address mask for MTRR since the base address in\r
+                                MTRR must align to 4K, so valid address mask equal to\r
+                                MtrrValidBitsMask & 0xfffffffffffff000ULL\r
+  @param  VariableMtrr          The array to shadow variable MTRRs content\r
+  @return                       The ruturn value of this paramter indicates the number of\r
+                                MTRRs which has been used.\r
+**/\r
+UINT32\r
+EFIAPI\r
+MtrrGetMemoryAttributeInVariableMtrr (\r
+  IN  UINT64                    MtrrValidBitsMask,\r
+  IN  UINT64                    MtrrValidAddressMask,\r
+  OUT VARIABLE_MTRR             *VariableMtrr\r
+  );\r
+\r
+\r
+/**\r
+  This function prints all MTRRs for debugging.\r
+**/\r
+VOID\r
+MtrrDebugPrintAllMtrrs (\r
+  );\r
+\r
+#endif // _MTRR_LIB_H_\r
diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/UefiCpuPkg/Library/MtrrLib/MtrrLib.c
new file mode 100644 (file)
index 0000000..dcd99b9
--- /dev/null
@@ -0,0 +1,1386 @@
+/** @file\r
+  MTRR setting library\r
+\r
+  Copyright (c) 2008 - 2009, Intel Corporation\r
+  All rights reserved. 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
+\r
+//\r
+// This table defines the offset, base and length of the fixed MTRRs\r
+//\r
+STATIC\r
+FIXED_MTRR    MtrrLibFixedMtrrTable[] = {\r
+  {\r
+    MTRR_LIB_IA32_MTRR_FIX64K_00000,\r
+    0,\r
+    SIZE_64KB\r
+  },\r
+  {\r
+    MTRR_LIB_IA32_MTRR_FIX16K_80000,\r
+    0x80000,\r
+    SIZE_16KB\r
+  },\r
+  {\r
+    MTRR_LIB_IA32_MTRR_FIX16K_A0000,\r
+    0xA0000,\r
+    SIZE_16KB\r
+  },\r
+  {\r
+    MTRR_LIB_IA32_MTRR_FIX4K_C0000,\r
+    0xC0000,\r
+    SIZE_4KB\r
+  },\r
+  {\r
+    MTRR_LIB_IA32_MTRR_FIX4K_C8000,\r
+    0xC8000,\r
+    SIZE_4KB\r
+  },\r
+  {\r
+    MTRR_LIB_IA32_MTRR_FIX4K_D0000,\r
+    0xD0000,\r
+    SIZE_4KB\r
+  },\r
+  {\r
+    MTRR_LIB_IA32_MTRR_FIX4K_D8000,\r
+    0xD8000,\r
+    SIZE_4KB\r
+  },\r
+  {\r
+    MTRR_LIB_IA32_MTRR_FIX4K_E0000,\r
+    0xE0000,\r
+    SIZE_4KB\r
+  },\r
+  {\r
+    MTRR_LIB_IA32_MTRR_FIX4K_E8000,\r
+    0xE8000,\r
+    SIZE_4KB\r
+  },\r
+  {\r
+    MTRR_LIB_IA32_MTRR_FIX4K_F0000,\r
+    0xF0000,\r
+    SIZE_4KB\r
+  },\r
+  {\r
+    MTRR_LIB_IA32_MTRR_FIX4K_F8000,\r
+    0xF8000,\r
+    SIZE_4KB\r
+  },\r
+};\r
+\r
+\r
+/**\r
+  Returns the default MTRR cache type for the system.\r
+\r
+  @return  MTRR default type\r
+\r
+**/\r
+UINT64\r
+GetMtrrDefaultMemoryType (\r
+  VOID\r
+)\r
+{\r
+  return (AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE) & 0xff);\r
+}\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
+  @return  CR4 value before changing.\r
+\r
+**/\r
+UINTN\r
+PreMtrrChange (\r
+  VOID\r
+  )\r
+{\r
+  UINTN  Value;\r
+\r
+  //\r
+  // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)\r
+  //\r
+  Value = AsmReadCr0 ();\r
+  Value = (UINTN) BitFieldWrite64 (Value, 30, 30, 1);\r
+  Value = (UINTN) BitFieldWrite64 (Value, 29, 29, 0);\r
+  AsmWriteCr0 (Value);\r
+  //\r
+  // Flush cache\r
+  //\r
+  AsmWbinvd ();\r
+  //\r
+  // Clear PGE flag Bit 7\r
+  //\r
+  Value = AsmReadCr4 ();\r
+  AsmWriteCr4 ((UINTN) BitFieldWrite64 (Value, 7, 7, 0));\r
+  //\r
+  // Flush all TLBs\r
+  //\r
+  CpuFlushTlb ();\r
+  //\r
+  // Disable Mtrrs\r
+  //\r
+  AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 0);\r
+\r
+  return Value;\r
+}\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  Cr4  CR4 value to restore\r
+\r
+**/\r
+VOID\r
+PostMtrrChange (\r
+  UINTN Cr4\r
+  )\r
+{\r
+  UINTN  Value;\r
+\r
+  //\r
+  // Enable Cache MTRR\r
+  //\r
+  AsmMsrBitFieldWrite64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, 10, 11, 3);\r
+\r
+  //\r
+  // Flush all TLBs and cache the second time\r
+  //\r
+  AsmWbinvd ();\r
+  CpuFlushTlb ();\r
+\r
+  //\r
+  // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)\r
+  //\r
+  Value = AsmReadCr0 ();\r
+  Value = (UINTN) BitFieldWrite64 (Value, 30, 30, 0);\r
+  Value = (UINTN) BitFieldWrite64 (Value, 29, 29, 0);\r
+  AsmWriteCr0 (Value);\r
+\r
+  AsmWriteCr4 (Cr4);\r
+\r
+  return ;\r
+}\r
+\r
+\r
+/**\r
+  Programs fixed MTRRs registers.\r
+\r
+  @param  MemoryCacheType  The memory type to set.\r
+  @param  Base             The base address of memory range.\r
+  @param  Length           The length of memory range.\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
+  )\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 >= MtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&\r
+        (*Base <\r
+            (\r
+              MtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
+              (8 * MtrrLibFixedMtrrTable[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
+           MtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
+           (ByteShift * MtrrLibFixedMtrrTable[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 >= MtrrLibFixedMtrrTable[MsrNum].Length));\r
+        ByteShift++\r
+      ) {\r
+    OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));\r
+    ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));\r
+    *Length -= MtrrLibFixedMtrrTable[MsrNum].Length;\r
+    *Base += MtrrLibFixedMtrrTable[MsrNum].Length;\r
+  }\r
+\r
+  if (ByteShift < 8 && (*Length != 0)) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  TempQword =\r
+    (AsmReadMsr64 (MtrrLibFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask;\r
+  AsmWriteMsr64 (MtrrLibFixedMtrrTable[MsrNum].Msr, TempQword);\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Get the attribute of variable MTRRs.\r
+\r
+  This function shadows the content of variable MTRRs into an\r
+  internal array: VariableMtrr.\r
+\r
+  @param  MtrrValidBitsMask     The mask for the valid bit of the MTRR\r
+  @param  MtrrValidAddressMask  The valid address mask for MTRR\r
+  @param  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
+  UINTN   Index;\r
+  UINT32  MsrNum;\r
+  UINT32  UsedMtrr;\r
+\r
+  ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+  UsedMtrr = 0;\r
+\r
+  for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE, Index = 0;\r
+       (\r
+         (MsrNum < MTRR_LIB_IA32_VARIABLE_MTRR_END) &&\r
+         (Index < FIRMWARE_VARIABLE_MTRR_NUMBER)\r
+       );\r
+       MsrNum += 2\r
+      ) {\r
+    if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
+      VariableMtrr[Index].Msr          = MsrNum;\r
+      VariableMtrr[Index].BaseAddress  = (AsmReadMsr64 (MsrNum) &\r
+                                          MtrrValidAddressMask);\r
+      VariableMtrr[Index].Length       = ((~(AsmReadMsr64 (MsrNum + 1) &\r
+                                             MtrrValidAddressMask)\r
+                                          ) &\r
+                                          MtrrValidBitsMask\r
+                                         ) + 1;\r
+      VariableMtrr[Index].Type         = (AsmReadMsr64 (MsrNum) & 0x0ff);\r
+      VariableMtrr[Index].Valid        = TRUE;\r
+      VariableMtrr[Index].Used         = TRUE;\r
+      UsedMtrr = UsedMtrr  + 1;\r
+      Index++;\r
+    }\r
+  }\r
+  return UsedMtrr;\r
+}\r
+\r
+\r
+/**\r
+  Checks overlap between given memory range and MTRRs.\r
+\r
+  @param  Start            The start address of memory range.\r
+  @param  End              The end address of memory range.\r
+  @param  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 PHYSICAL_ADDRESS     Start,\r
+  IN PHYSICAL_ADDRESS     End,\r
+  IN VARIABLE_MTRR      *VariableMtrr\r
+  )\r
+{\r
+  UINT32  Index;\r
+\r
+  for (Index = 0; Index < 6; 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  Index         The index of the array VariableMtrr to be invalidated\r
+  @param  VariableMtrr  The array to shadow variable MTRRs content\r
+  @param  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
+  Combine memory attributes.\r
+\r
+  If overlap exists between given memory range and MTRRs, try to combine them.\r
+\r
+  @param  Attributes             The memory type to set.\r
+  @param  Base                   The base address of memory range.\r
+  @param  Length                 The length of memory range.\r
+  @param  VariableMtrr           The array to shadow variable MTRRs content\r
+  @param  UsedMtrr               The number of MTRRs which has already been used\r
+  @param  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     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
+\r
+  *OverwriteExistingMtrr = FALSE;\r
+  EndAddress = *Base +*Length - 1;\r
+\r
+  for (Index = 0; Index < FIRMWARE_VARIABLE_MTRR_NUMBER; 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, return RETURN_SUCCESS\r
+      //\r
+      if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {\r
+        *Length = 0;\r
+        return RETURN_SUCCESS;\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
+  return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Calculate the maximum value which is a power of 2, but less the MemoryLength.\r
+\r
+  @param  MemoryLength        The number to pass in.\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)) {\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
+  Check the direction to program variable MTRRs.\r
+\r
+  This function determines which direction of programming the variable\r
+  MTRRs will use fewer MTRRs.\r
+\r
+  @param  Input       Length of Memory to program MTRR\r
+  @param  MtrrNumber  Pointer to the number of necessary MTRRs\r
+\r
+  @retval TRUE        Positive direction is better.\r
+          FALSE       Negtive direction is better.\r
+\r
+**/\r
+BOOLEAN\r
+GetDirection (\r
+  IN UINT64      Input,\r
+  IN UINTN       *MtrrNumber\r
+  )\r
+{\r
+  UINT64  TempQword;\r
+  UINT32  Positive;\r
+  UINT32  Subtractive;\r
+\r
+  TempQword   = Input;\r
+  Positive    = 0;\r
+  Subtractive = 0;\r
+\r
+  do {\r
+    TempQword -= Power2MaxMemory (TempQword);\r
+    Positive++;\r
+  } while (TempQword != 0);\r
+\r
+  TempQword = Power2MaxMemory (LShiftU64 (Input, 1)) - Input;\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  VariableMtrr   The array to shadow variable MTRRs content\r
+\r
+**/\r
+STATIC\r
+VOID\r
+InvalidateMtrr (\r
+   IN     VARIABLE_MTRR      *VariableMtrr\r
+   )\r
+{\r
+  UINTN Index;\r
+  UINTN Cr4;\r
+\r
+  Cr4 = PreMtrrChange ();\r
+  Index = 0;\r
+  while (Index < MTRR_NUMBER_OF_VARIABLE_MTRR) {\r
+    if (VariableMtrr[Index].Valid == FALSE && VariableMtrr[Index].Used == TRUE ) {\r
+       AsmWriteMsr64 (VariableMtrr[Index].Msr, 0);\r
+       AsmWriteMsr64 (VariableMtrr[Index].Msr + 1, 0);\r
+       VariableMtrr[Index].Used = FALSE;\r
+    }\r
+    Index ++;\r
+  }\r
+  PostMtrrChange (Cr4);\r
+}\r
+\r
+\r
+/**\r
+  Programs variable MTRRs\r
+\r
+  This function programs variable MTRRs\r
+\r
+  @param  MtrrNumber            Index of MTRR to program.\r
+  @param  BaseAddress           Base address of memory region.\r
+  @param  Length                Length of memory region.\r
+  @param  MemoryCacheType       Memory type to set.\r
+  @param  MtrrValidAddressMask  The valid address mask for MTRR\r
+\r
+**/\r
+STATIC\r
+VOID\r
+ProgramVariableMtrr (\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
+  UINTN   Cr4;\r
+\r
+  Cr4 = PreMtrrChange ();\r
+\r
+  //\r
+  // MTRR Physical Base\r
+  //\r
+  TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
+  AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);\r
+\r
+  //\r
+  // MTRR Physical Mask\r
+  //\r
+  TempQword = ~(Length - 1);\r
+  AsmWriteMsr64 (\r
+    (UINT32) (MtrrNumber + 1),\r
+    (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED\r
+    );\r
+\r
+  PostMtrrChange (Cr4);\r
+}\r
+\r
+\r
+/**\r
+  Convert the Memory attibute value to MTRR_MEMORY_CACHE_TYPE.\r
+\r
+  @param  MtrrType  MTRR memory type\r
+\r
+  @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
+\r
+**/\r
+STATIC\r
+MTRR_MEMORY_CACHE_TYPE\r
+GetMemoryCacheTypeFromMtrrType (\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 CacheUncacheable;\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  MtrrValidBitsMask     The mask for the valid bit of the MTRR\r
+  @param  MtrrValidAddressMask  The valid address mask for the MTRR\r
+\r
+**/\r
+STATIC\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_CACHE_VALID_ADDRESS;\r
+    *MtrrValidAddressMask = 0xFFFFFFFF;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Determing 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 MTRR 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  MtrrType1    the first kind of Memory type\r
+  @param  MtrrType2    the second kind of memory type\r
+\r
+**/\r
+UINT64\r
+MtrrPrecedence (\r
+  UINT64    MtrrType1,\r
+  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
+/**\r
+  This function attempts to set the attributes for a memory range.\r
+\r
+  @param  BaseAddress            The physical address that is the start\r
+                                 address of a memory region.\r
+  @param  Length                 The size in bytes of the memory region.\r
+  @param  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
+  UINT64                    TempQword;\r
+  RETURN_STATUS             Status;\r
+  UINT64                    MemoryType;\r
+  UINT64                    Remainder;\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
+  UINTN                     Cr4;\r
+  BOOLEAN                   OverwriteExistingMtrr;\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
+    return RETURN_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (\r
+       (BaseAddress &~MtrrValidAddressMask) != 0 ||\r
+       (Length &~MtrrValidAddressMask) != 0\r
+     ) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Check if Fixed MTRR\r
+  //\r
+  Status = RETURN_SUCCESS;\r
+  while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
+    Cr4 = PreMtrrChange ();\r
+    Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length);\r
+    PostMtrrChange (Cr4);\r
+    if (RETURN_ERROR (Status)) {\r
+      return Status;\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
+  // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
+  // we can set the bade to 0 to save variable MTRRs.\r
+  //\r
+  if (BaseAddress == BASE_1MB) {\r
+    BaseAddress = 0;\r
+    Length += SIZE_1MB;\r
+  }\r
+\r
+  //\r
+  // Check memory base address alignment\r
+  //\r
+  DivU64x64Remainder (BaseAddress, Power2MaxMemory (LShiftU64 (Length, 1)), &Remainder);\r
+  if (Remainder != 0) {\r
+    DivU64x64Remainder (BaseAddress, Power2MaxMemory (Length), &Remainder);\r
+    if (Remainder != 0) {\r
+      Status = RETURN_UNSUPPORTED;\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check for overlap\r
+  //\r
+  UsedMtrr = MtrrGetMemoryAttributeInVariableMtrr (MtrrValidBitsMask, MtrrValidAddressMask, VariableMtrr);\r
+  OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1, VariableMtrr);\r
+  if (OverLap) {\r
+    Status = CombineMemoryAttribute (MemoryType, &BaseAddress, &Length, VariableMtrr, &UsedMtrr, &OverwriteExistingMtrr);\r
+    if (RETURN_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    if (Length == 0) {\r
+      //\r
+      // Combined successfully\r
+      //\r
+      Status = RETURN_SUCCESS;\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Program Variable MTRRs\r
+  //\r
+  // Avoid hardcode here and read data dynamically\r
+  //\r
+  if (UsedMtrr >= FIRMWARE_VARIABLE_MTRR_NUMBER) {\r
+    Status = RETURN_OUT_OF_RESOURCES;\r
+    goto Done;\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 == GetMtrrDefaultMemoryType ())) {\r
+    //\r
+    // Invalidate the now-unused MTRRs\r
+    //\r
+    InvalidateMtrr(VariableMtrr);\r
+    goto Done;\r
+  }\r
+\r
+  TempQword = Length;\r
+\r
+\r
+  if (TempQword == Power2MaxMemory (TempQword)) {\r
+    //\r
+    // Invalidate the now-unused MTRRs\r
+    //\r
+    InvalidateMtrr(VariableMtrr);\r
+\r
+    //\r
+    // Find first unused MTRR\r
+    //\r
+    for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
+         MsrNum < MTRR_LIB_IA32_VARIABLE_MTRR_END;\r
+         MsrNum += 2\r
+        ) {\r
+      if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    ProgramVariableMtrr (\r
+      MsrNum,\r
+      BaseAddress,\r
+      Length,\r
+      MemoryType,\r
+      MtrrValidAddressMask\r
+      );\r
+  } else {\r
+\r
+    Positive = GetDirection (TempQword, &MtrrNumber);\r
+\r
+    if ((UsedMtrr + MtrrNumber) > FIRMWARE_VARIABLE_MTRR_NUMBER) {\r
+      Status = RETURN_OUT_OF_RESOURCES;\r
+      goto Done;\r
+    }\r
+\r
+    //\r
+    // Invalidate the now-unused MTRRs\r
+    //\r
+    InvalidateMtrr(VariableMtrr);\r
+\r
+    //\r
+    // Find first unused MTRR\r
+    //\r
+    for (MsrNum = MTRR_LIB_IA32_VARIABLE_MTRR_BASE;\r
+         MsrNum < MTRR_LIB_IA32_VARIABLE_MTRR_END;\r
+         MsrNum += 2\r
+        ) {\r
+      if ((AsmReadMsr64 (MsrNum + 1) & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    if (!Positive) {\r
+      Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
+      ProgramVariableMtrr (\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 < MTRR_LIB_IA32_VARIABLE_MTRR_END; MsrNum += 2) {\r
+        if ((AsmReadMsr64 (MsrNum + 1) & 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
+        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
+\r
+Done:\r
+  return Status;\r
+\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  Address   The specific address\r
+\r
+  @return Memory cache type of the sepcific address\r
+\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+EFIAPI\r
+MtrrGetMemoryAttribute (\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
+\r
+  //\r
+  // Check if MTRR is enabled, if not, return UC as attribute\r
+  //\r
+  TempQword = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\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 >= MtrrLibFixedMtrrTable[Index].BaseAddress &&\r
+             Address  < (\r
+                          MtrrLibFixedMtrrTable[Index].BaseAddress +\r
+                          (MtrrLibFixedMtrrTable[Index].Length * 8)\r
+                        )\r
+            ) {\r
+           SubIndex =\r
+             ((UINTN)Address - MtrrLibFixedMtrrTable[Index].BaseAddress) /\r
+               MtrrLibFixedMtrrTable[Index].Length;\r
+           TempQword = AsmReadMsr64 (MtrrLibFixedMtrrTable[Index].Msr);\r
+           MtrrType =  RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
+           return GetMemoryCacheTypeFromMtrrType (MtrrType);\r
+         }\r
+      }\r
+    }\r
+  }\r
+  MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
+  MtrrGetMemoryAttributeInVariableMtrr(\r
+    MtrrValidBitsMask,\r
+    MtrrValidAddressMask,\r
+    VariableMtrr\r
+    );\r
+\r
+  //\r
+  // Go through the variable MTRR\r
+  //\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_VARIABLE_MTRR; 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 (MtrrType);\r
+\r
+  return CacheType;\r
+}\r
+\r
+\r
+/**\r
+  This function will get the raw value in variable MTRRs\r
+\r
+  @param  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
+  UINT32  Index;\r
+\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_VARIABLE_MTRR; Index++) {\r
+    VariableSettings->Mtrr[Index].Base =\r
+      AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1));\r
+    VariableSettings->Mtrr[Index].Mask =\r
+      AsmReadMsr64 (MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1);\r
+  }\r
+\r
+  return  VariableSettings;\r
+}\r
+\r
+\r
+/**\r
+  Worker function setting variable MTRRs\r
+\r
+  @param  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
+\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_VARIABLE_MTRR; Index++) {\r
+    AsmWriteMsr64 (\r
+      MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1),\r
+      VariableSettings->Mtrr[Index].Base\r
+      );\r
+    AsmWriteMsr64 (\r
+      MTRR_LIB_IA32_VARIABLE_MTRR_BASE + (Index << 1) + 1,\r
+      VariableSettings->Mtrr[Index].Mask\r
+      );\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This function sets variable MTRRs\r
+\r
+  @param  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
+  UINTN  Cr4;\r
+\r
+  Cr4 = PreMtrrChange ();\r
+  MtrrSetVariableMtrrWorker (VariableSettings);\r
+  PostMtrrChange (Cr4);\r
+  return  VariableSettings;\r
+}\r
+\r
+\r
+/**\r
+  This function gets the content in fixed MTRRs\r
+\r
+  @param  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
+  UINT32  Index;\r
+\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+      FixedSettings->Mtrr[Index] =\r
+        AsmReadMsr64 (MtrrLibFixedMtrrTable[Index].Msr);\r
+  };\r
+\r
+  return FixedSettings;\r
+}\r
+\r
+/**\r
+  Worker function setting fixed MTRRs\r
+\r
+  @param  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
+     AsmWriteMsr64 (\r
+       MtrrLibFixedMtrrTable[Index].Msr,\r
+       FixedSettings->Mtrr[Index]\r
+       );\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This function sets fixed MTRRs\r
+\r
+  @param  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
+  UINTN  Cr4;\r
+\r
+  Cr4 = PreMtrrChange ();\r
+  MtrrSetFixedMtrrWorker (FixedSettings);\r
+  PostMtrrChange (Cr4);\r
+\r
+  return FixedSettings;\r
+}\r
+\r
+\r
+/**\r
+  This function gets the content in all MTRRs (variable and fixed)\r
+\r
+  @param  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
+  //\r
+  // Get fixed MTRRs\r
+  //\r
+  MtrrGetFixedMtrr (&MtrrSetting->Fixed);\r
+\r
+  //\r
+  // Get variable MTRRs\r
+  //\r
+  MtrrGetVariableMtrr (&MtrrSetting->Variables);\r
+\r
+  //\r
+  // Get MTRR_DEF_TYPE value\r
+  //\r
+  MtrrSetting->MtrrDefType = AsmReadMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE);\r
+\r
+  return MtrrSetting;\r
+}\r
+\r
+\r
+/**\r
+  This function sets all MTRRs (variable and fixed)\r
+\r
+  @param  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
+  UINTN  Cr4;\r
+\r
+  Cr4 = PreMtrrChange ();\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
+  AsmWriteMsr64 (MTRR_LIB_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
+\r
+  PostMtrrChange (Cr4);\r
+\r
+  return MtrrSetting;\r
+}\r
+\r
+\r
+/**\r
+  This function prints all MTRRs for debugging.\r
+**/\r
+VOID\r
+MtrrDebugPrintAllMtrrs (\r
+  )\r
+{\r
+  DEBUG_CODE (\r
+    {\r
+      MTRR_SETTINGS  MtrrSettings;\r
+      UINTN          Index;\r
+\r
+      MtrrGetAllMtrrs (&MtrrSettings);\r
+      DEBUG((EFI_D_ERROR, "DefaultType = %016lx\n", MtrrSettings.MtrrDefType));\r
+      for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+        DEBUG((\r
+          EFI_D_ERROR, "Fixed[%02d] = %016lx\n",\r
+          Index,\r
+          MtrrSettings.Fixed.Mtrr[Index]\r
+          ));\r
+      }\r
+      for (Index = 0; Index < MTRR_NUMBER_OF_VARIABLE_MTRR; Index++) {\r
+        DEBUG((\r
+          EFI_D_ERROR, "Variable[%02d] = %016lx, %016lx\n",\r
+          Index,\r
+          MtrrSettings.Variables.Mtrr[Index].Base,\r
+          MtrrSettings.Variables.Mtrr[Index].Mask\r
+          ));\r
+      }\r
+    }\r
+  );\r
+}\r
+\r
diff --git a/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf b/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf
new file mode 100644 (file)
index 0000000..67b0340
--- /dev/null
@@ -0,0 +1,44 @@
+#/** @file\r
+#  MTRR library provides API for MTRR operation\r
+#\r
+#  Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
+#  All rights reserved. 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
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = MtrrLib\r
+  FILE_GUID                      = 6826b408-f4f3-47ee-917f-af7047f9d937\r
+  MODULE_TYPE                    = BASE\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = MtrrLib \r
+  EDK_RELEASE_VERSION            = 0x00020000\r
+  EFI_SPECIFICATION_VERSION      = 0x00020000\r
+\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64\r
+#\r
+\r
+[Sources.common]\r
+  MtrrLib.c\r
+\r
+[Packages]\r
+  OvmfPkg/OvmfPkg.dec\r
+  MdePkg/MdePkg.dec\r
+  UefiCpuPkg/UefiCpuPkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseMemoryLib\r
+  BaseLib\r
+  CpuLib\r
+\r
index 60bf5f09c454f8973f0d6b8c6db847b33d5edbd6..4a249c1d70a33bf61fccac0d492343c4ca3cdd6a 100644 (file)
@@ -1,24 +1,26 @@
-##  @file  UefiCpuPkg.dec\r
-#\r
-# This Package provides UEFI compatible CPU modules and libraries.\r
-#\r
-# Copyright (c) 2007 - 2009, Intel Corporation.\r
-#\r
-# All rights reserved.\r
-# This program and the accompanying materials are licensed and made available under\r
-# the terms and conditions of the BSD License which accompanies this distribution.\r
-# 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
-[Defines]\r
-  DEC_SPECIFICATION              = 0x00010005\r
-  PACKAGE_NAME                   = UefiCpuPkg\r
-  PACKAGE_GUID                   = 2171df9b-0d39-45aa-ac37-2de190010d23\r
-  PACKAGE_VERSION                = 0.1\r
-\r
+##  @file  UefiCpuPkg.dec
+#
+# This Package provides UEFI compatible CPU modules and libraries.
+#
+# Copyright (c) 2007 - 2009, Intel Corporation.
+#
+# All rights reserved.
+# This program and the accompanying materials are licensed and made available under
+# the terms and conditions of the BSD License which accompanies this distribution.
+# The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  DEC_SPECIFICATION              = 0x00010005
+  PACKAGE_NAME                   = UefiCpuPkg
+  PACKAGE_GUID                   = 2171df9b-0d39-45aa-ac37-2de190010d23
+  PACKAGE_VERSION                = 0.1
+
+[Includes.common]
+  Include