+ }\r
+\r
+ Status = RETURN_SUCCESS;\r
+ MtrrLibCalculateLeastMtrrs ((UINT16) VectorCount, Vector, Weight, 0, (UINT16) VectorCount - 1, FALSE);\r
+ Stop = (UINT16) VectorCount - 1;\r
+ while (Stop != 0) {\r
+ Start = Vector[Stop].Previous;\r
+ TypeCount = MAX_UINT8;\r
+ Type = 0;\r
+ if (Weight[M(Start, Stop)] != 0) {\r
+ TypeCount = MtrrLibGetNumberOfTypes (Ranges, RangeCount, Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, &Type);\r
+ Status = MtrrLibAppendVariableMtrr (\r
+ Mtrrs, MtrrCapacity, MtrrCount,\r
+ Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, \r
+ MtrrLibLowestType (Type)\r
+ );\r
+ if (RETURN_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Start != Stop - 1) {\r
+ //\r
+ // substractive path\r
+ //\r
+ if (TypeCount == MAX_UINT8) {\r
+ TypeCount = MtrrLibGetNumberOfTypes (\r
+ Ranges, RangeCount, Vector[Start].Address, Vector[Stop].Address - Vector[Start].Address, &Type\r
+ );\r
+ }\r
+ Status = MtrrLibCalculateSubtractivePath (\r
+ DefaultType, A0,\r
+ Ranges, RangeCount,\r
+ (UINT16) VectorCount, Vector, Weight, Start, Stop,\r
+ Type, TypeCount,\r
+ Mtrrs, MtrrCapacity, MtrrCount\r
+ );\r
+ if (RETURN_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+ Stop = Start;\r
+ }\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Apply the fixed MTRR settings to memory range array.\r
+\r
+ @param Fixed The fixed MTRR settings.\r
+ @param Ranges Return the memory range array holding memory type\r
+ settings for all memory address.\r
+ @param RangeCapacity The capacity of memory range array.\r
+ @param RangeCount Return the count of memory range.\r
+\r
+ @retval RETURN_SUCCESS The memory range array is returned successfully.\r
+ @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibApplyFixedMtrrs (\r
+ IN MTRR_FIXED_SETTINGS *Fixed,\r
+ IN OUT MTRR_MEMORY_RANGE *Ranges,\r
+ IN UINTN RangeCapacity,\r
+ IN OUT UINTN *RangeCount\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ UINTN MsrIndex;\r
+ UINTN Index;\r
+ MTRR_MEMORY_CACHE_TYPE MemoryType;\r
+ UINT64 Base;\r
+\r
+ Base = 0;\r
+ for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {\r
+ ASSERT (Base == mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress);\r
+ for (Index = 0; Index < sizeof (UINT64); Index++) {\r
+ MemoryType = (MTRR_MEMORY_CACHE_TYPE)((UINT8 *)(&Fixed->Mtrr[MsrIndex]))[Index];\r
+ Status = MtrrLibSetMemoryType (\r
+ Ranges, RangeCapacity, RangeCount, Base, mMtrrLibFixedMtrrTable[MsrIndex].Length, MemoryType\r
+ );\r
+ if (Status == RETURN_OUT_OF_RESOURCES) {\r
+ return Status;\r
+ }\r
+ Base += mMtrrLibFixedMtrrTable[MsrIndex].Length;\r
+ }\r
+ }\r
+ ASSERT (Base == BASE_1MB);\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+ Apply the variable MTRR settings to memory range array.\r
+\r
+ @param VariableMtrr The variable MTRR array.\r
+ @param VariableMtrrCount The count of variable MTRRs.\r
+ @param Ranges Return the memory range array with new MTRR settings applied.\r
+ @param RangeCapacity The capacity of memory range array.\r
+ @param RangeCount Return the count of memory range.\r
+\r
+ @retval RETURN_SUCCESS The memory range array is returned successfully.\r
+ @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibApplyVariableMtrrs (\r
+ IN CONST MTRR_MEMORY_RANGE *VariableMtrr,\r
+ IN UINT32 VariableMtrrCount,\r
+ IN OUT MTRR_MEMORY_RANGE *Ranges,\r
+ IN UINTN RangeCapacity,\r
+ IN OUT UINTN *RangeCount\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ UINTN Index;\r
+\r
+ //\r
+ // WT > WB\r
+ // UC > *\r
+ // UC > * (except WB, UC) > WB\r
+ //\r
+\r
+ //\r
+ // 1. Set WB\r
+ //\r
+ for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+ if ((VariableMtrr[Index].Length != 0) && (VariableMtrr[Index].Type == CacheWriteBack)) {\r
+ Status = MtrrLibSetMemoryType (\r
+ Ranges, RangeCapacity, RangeCount,\r
+ VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type\r
+ );\r
+ if (Status == RETURN_OUT_OF_RESOURCES) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // 2. Set other types than WB or UC\r
+ //\r
+ for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+ if ((VariableMtrr[Index].Length != 0) && \r
+ (VariableMtrr[Index].Type != CacheWriteBack) && (VariableMtrr[Index].Type != CacheUncacheable)) {\r
+ Status = MtrrLibSetMemoryType (\r
+ Ranges, RangeCapacity, RangeCount,\r
+ VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type\r
+ );\r
+ if (Status == RETURN_OUT_OF_RESOURCES) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // 3. Set UC\r
+ //\r
+ for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+ if (VariableMtrr[Index].Length != 0 && VariableMtrr[Index].Type == CacheUncacheable) {\r
+ Status = MtrrLibSetMemoryType (\r
+ Ranges, RangeCapacity, RangeCount,\r
+ VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type\r
+ );\r
+ if (Status == RETURN_OUT_OF_RESOURCES) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+ Return the memory type bit mask that's compatible to first type in the Ranges.\r
+\r
+ @param Ranges Memory range array holding the memory type\r
+ settings for all memory address.\r
+ @param RangeCount Count of memory ranges.\r
+\r
+ @return Compatible memory type bit mask.\r
+**/\r
+UINT8\r
+MtrrLibGetCompatibleTypes (\r
+ IN CONST MTRR_MEMORY_RANGE *Ranges,\r
+ IN UINTN RangeCount\r
+ )\r
+{\r
+ ASSERT (RangeCount != 0);\r
+\r
+ switch (Ranges[0].Type) {\r
+ case CacheWriteBack:\r
+ case CacheWriteThrough:\r
+ return (1 << CacheWriteBack) | (1 << CacheWriteThrough) | (1 << CacheUncacheable);\r
+ break;\r
+\r
+ case CacheWriteCombining:\r
+ case CacheWriteProtected:\r
+ return (1 << Ranges[0].Type) | (1 << CacheUncacheable);\r
+ break;\r
+\r
+ case CacheUncacheable:\r
+ if (RangeCount == 1) {\r
+ return (1 << CacheUncacheable);\r
+ }\r
+ return MtrrLibGetCompatibleTypes (&Ranges[1], RangeCount - 1);\r
+ break;\r
+\r
+ case CacheInvalid:\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Overwrite the destination MTRR settings with the source MTRR settings.\r
+ This routine is to make sure the modification to destination MTRR settings\r
+ is as small as possible.\r
+\r
+ @param DstMtrrs Destination MTRR settings.\r
+ @param DstMtrrCount Count of destination MTRR settings.\r
+ @param SrcMtrrs Source MTRR settings.\r
+ @param SrcMtrrCount Count of source MTRR settings.\r
+ @param Modified Flag array to indicate which destination MTRR setting is modified.\r
+**/\r
+VOID\r
+MtrrLibMergeVariableMtrr (\r
+ MTRR_MEMORY_RANGE *DstMtrrs,\r
+ UINT32 DstMtrrCount,\r
+ MTRR_MEMORY_RANGE *SrcMtrrs,\r
+ UINT32 SrcMtrrCount,\r
+ BOOLEAN *Modified\r
+ )\r
+{\r
+ UINT32 DstIndex;\r
+ UINT32 SrcIndex;\r