--- /dev/null
+/** @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
--- /dev/null
+/** @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