+ if (LengthLeft != 0) {\r
+ Ranges[StartIndex].Length = LengthLeft;\r
+ StartIndex++;\r
+ }\r
+ if (LengthRight != 0) {\r
+ Ranges[EndIndex - DeltaCount].BaseAddress = BaseAddress + Length;\r
+ Ranges[EndIndex - DeltaCount].Length = LengthRight;\r
+ Ranges[EndIndex - DeltaCount].Type = Ranges[EndIndex].Type;\r
+ }\r
+ Ranges[StartIndex].BaseAddress = BaseAddress;\r
+ Ranges[StartIndex].Length = Length;\r
+ Ranges[StartIndex].Type = Type;\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+ Allocate one or more variable MTRR to cover the range identified by\r
+ BaseAddress and Length.\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
+ @param VariableMtrr Variable MTRR array.\r
+ @param VariableMtrrCapacity Capacity of variable MTRR array.\r
+ @param VariableMtrrCount Count of variable MTRR.\r
+ @param BaseAddress Base address of the memory range.\r
+ @param Length Length of the memory range.\r
+ @param Type MTRR type of the memory range.\r
+ @param Alignment0 Alignment of 0.\r
+\r
+ @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
+ @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibSetMemoryAttributeInVariableMtrr (\r
+ IN CONST MEMORY_RANGE *Ranges,\r
+ IN UINT32 RangeCount,\r
+ IN OUT VARIABLE_MTRR *VariableMtrr,\r
+ IN UINT32 VariableMtrrCapacity,\r
+ IN OUT UINT32 *VariableMtrrCount,\r
+ IN UINT64 BaseAddress,\r
+ IN UINT64 Length,\r
+ IN MTRR_MEMORY_CACHE_TYPE Type,\r
+ IN UINT64 Alignment0\r
+ );\r
+\r
+/**\r
+ Allocate one or more variable MTRR to cover the range identified by\r
+ BaseAddress and Length.\r
+\r
+ The routine recursively calls MtrrLibSetMemoryAttributeInVariableMtrr()\r
+ to allocate variable MTRRs when the range contains several sub-ranges\r
+ with different attributes.\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
+ @param VariableMtrr Variable MTRR array.\r
+ @param VariableMtrrCapacity Capacity of variable MTRR array.\r
+ @param VariableMtrrCount Count of variable MTRR.\r
+ @param BaseAddress Base address of the memory range.\r
+ @param Length Length of the memory range.\r
+ @param Type MTRR type of the range.\r
+ If it's CacheInvalid, the memory range may\r
+ contains several sub-ranges with different\r
+ attributes.\r
+ @param Alignment0 Alignment of 0.\r
+\r
+ @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
+ @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibAddVariableMtrr (\r
+ IN CONST MEMORY_RANGE *Ranges,\r
+ IN UINT32 RangeCount,\r
+ IN OUT VARIABLE_MTRR *VariableMtrr,\r
+ IN UINT32 VariableMtrrCapacity,\r
+ IN OUT UINT32 *VariableMtrrCount,\r
+ IN PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN MTRR_MEMORY_CACHE_TYPE Type,\r
+ IN UINT64 Alignment0\r
+)\r
+{\r
+ RETURN_STATUS Status;\r
+ UINT32 Index;\r
+ UINT64 SubLength;\r
+\r
+ MTRR_LIB_ASSERT_ALIGNED (BaseAddress, Length);\r
+ if (Type == CacheInvalid) {\r
+ ASSERT (Ranges != NULL);\r
+ for (Index = 0; Index < RangeCount; Index++) {\r
+ if (Ranges[Index].BaseAddress <= BaseAddress && BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
+\r
+ //\r
+ // Because the Length may not be aligned to BaseAddress, below code calls\r
+ // MtrrLibSetMemoryAttributeInVariableMtrr() instead of itself.\r
+ // MtrrLibSetMemoryAttributeInVariableMtrr() splits the range to several\r
+ // aligned ranges.\r
+ //\r
+ if (Ranges[Index].BaseAddress + Ranges[Index].Length >= BaseAddress + Length) {\r
+ return MtrrLibSetMemoryAttributeInVariableMtrr (\r
+ Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+ BaseAddress, Length, Ranges[Index].Type, Alignment0\r
+ );\r
+ } else {\r
+ SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress;\r
+ Status = MtrrLibSetMemoryAttributeInVariableMtrr (\r
+ Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+ BaseAddress, SubLength, Ranges[Index].Type, Alignment0\r
+ );\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ BaseAddress += SubLength;\r
+ Length -= SubLength;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Because memory ranges cover all the memory addresses, it's impossible to be here.\r
+ //\r
+ ASSERT (FALSE);\r
+ return RETURN_DEVICE_ERROR;\r
+ } else {\r
+ for (Index = 0; Index < *VariableMtrrCount; Index++) {\r
+ if (VariableMtrr[Index].BaseAddress == BaseAddress && VariableMtrr[Index].Length == Length) {\r
+ ASSERT (VariableMtrr[Index].Type == Type);\r
+ break;\r
+ }\r
+ }\r
+ if (Index == *VariableMtrrCount) {\r
+ if (*VariableMtrrCount == VariableMtrrCapacity) {\r
+ return RETURN_OUT_OF_RESOURCES;\r
+ }\r
+ VariableMtrr[Index].BaseAddress = BaseAddress;\r
+ VariableMtrr[Index].Length = Length;\r
+ VariableMtrr[Index].Type = Type;\r
+ VariableMtrr[Index].Valid = TRUE;\r
+ VariableMtrr[Index].Used = TRUE;\r
+ (*VariableMtrrCount)++;\r
+ }\r
+ return RETURN_SUCCESS;\r
+ }\r
+}\r
+\r
+/**\r
+ Allocate one or more variable MTRR to cover the range identified by\r
+ BaseAddress and Length.\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
+ @param VariableMtrr Variable MTRR array.\r
+ @param VariableMtrrCapacity Capacity of variable MTRR array.\r
+ @param VariableMtrrCount Count of variable MTRR.\r
+ @param BaseAddress Base address of the memory range.\r
+ @param Length Length of the memory range.\r
+ @param Type MTRR type of the memory range.\r
+ @param Alignment0 Alignment of 0.\r
+\r
+ @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.\r
+ @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibSetMemoryAttributeInVariableMtrr (\r
+ IN CONST MEMORY_RANGE *Ranges,\r
+ IN UINT32 RangeCount,\r
+ IN OUT VARIABLE_MTRR *VariableMtrr,\r
+ IN UINT32 VariableMtrrCapacity,\r
+ IN OUT UINT32 *VariableMtrrCount,\r
+ IN UINT64 BaseAddress,\r
+ IN UINT64 Length,\r
+ IN MTRR_MEMORY_CACHE_TYPE Type,\r
+ IN UINT64 Alignment0\r
+)\r
+{\r
+ UINT64 Alignment;\r
+ UINT32 MtrrNumber;\r
+ UINT32 SubtractiveLeft;\r
+ UINT32 SubtractiveRight;\r
+ BOOLEAN UseLeastAlignment;\r
+\r
+ Alignment = 0;\r
+\r
+ MtrrNumber = MtrrLibGetMtrrNumber (Ranges, RangeCount, VariableMtrr, *VariableMtrrCount,\r
+ BaseAddress, Length, Type, Alignment0, &SubtractiveLeft, &SubtractiveRight);\r
+\r
+ if (MtrrNumber + *VariableMtrrCount > VariableMtrrCapacity) {\r
+ return RETURN_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ while (SubtractiveLeft-- != 0) {\r
+ Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
+ ASSERT (Alignment <= Length);\r
+\r
+ MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+ BaseAddress - Alignment, Alignment, CacheInvalid, Alignment0);\r
+ BaseAddress -= Alignment;\r
+ Length += Alignment;\r
+ }\r
+\r
+ while (Length != 0) {\r
+ Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
+ if (Alignment > Length) {\r
+ break;\r
+ }\r
+ MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+ BaseAddress, Alignment, Type, Alignment0);\r
+ BaseAddress += Alignment;\r
+ Length -= Alignment;\r
+ }\r
+\r
+ while (SubtractiveRight-- != 0) {\r
+ Alignment = MtrrLibLeastAlignment (BaseAddress + Length, Alignment0);\r
+ MtrrLibAddVariableMtrr (Ranges, RangeCount, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+ BaseAddress + Length, Alignment, CacheInvalid, Alignment0);\r
+ Length += Alignment;\r
+ }\r
+\r
+ UseLeastAlignment = TRUE;\r
+ while (Length != 0) {\r
+ if (UseLeastAlignment) {\r
+ Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
+ if (Alignment > Length) {\r
+ UseLeastAlignment = FALSE;\r
+ }\r
+ }\r
+\r
+ if (!UseLeastAlignment) {\r
+ Alignment = GetPowerOfTwo64 (Length);\r
+ }\r
+\r
+ MtrrLibAddVariableMtrr (NULL, 0, VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+ BaseAddress, Alignment, Type, Alignment0);\r
+ BaseAddress += Alignment;\r
+ Length -= Alignment;\r
+ }\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+ Return an array of memory ranges holding memory type settings for all memory\r
+ address.\r
+\r
+ @param DefaultType The default memory type.\r
+ @param TotalLength The total length of the memory.\r
+ @param VariableMtrr The variable MTRR array.\r
+ @param VariableMtrrCount The count of variable MTRRs.\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
+MtrrLibGetMemoryTypes (\r
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
+ IN UINT64 TotalLength,\r
+ IN CONST VARIABLE_MTRR *VariableMtrr,\r
+ IN UINT32 VariableMtrrCount,\r
+ OUT MEMORY_RANGE *Ranges,\r
+ IN UINT32 RangeCapacity,\r
+ OUT UINT32 *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
+ // 0. Set whole range as DefaultType\r
+ //\r
+ *RangeCount = 1;\r
+ Ranges[0].BaseAddress = 0;\r
+ Ranges[0].Length = TotalLength;\r
+ Ranges[0].Type = DefaultType;\r
+\r
+ //\r
+ // 1. Set WB\r
+ //\r
+ for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+ if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheWriteBack) {\r
+ Status = MtrrLibSetMemoryType (\r
+ Ranges, RangeCapacity, RangeCount,\r
+ VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
+ );\r
+ if (RETURN_ERROR (Status)) {\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].Valid && VariableMtrr[Index].Type != CacheWriteBack && VariableMtrr[Index].Type != CacheUncacheable) {\r
+ Status = MtrrLibSetMemoryType (\r
+ Ranges, RangeCapacity, RangeCount,\r
+ VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
+ );\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // 3. Set UC\r
+ //\r
+ for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+ if (VariableMtrr[Index].Valid && VariableMtrr[Index].Type == CacheUncacheable) {\r
+ Status = MtrrLibSetMemoryType (\r
+ Ranges, RangeCapacity, RangeCount,\r
+ VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type\r
+ );\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+ Worker function attempts to set the attributes for a memory range.\r
+\r
+ If MtrrSetting is not NULL, set the attributes into the input MTRR\r
+ settings buffer.\r
+ If MtrrSetting is NULL, set the attributes into MTRRs registers.\r
+\r
+ @param[in, out] MtrrSetting A buffer holding all MTRRs content.\r