-\r
-/**\r
- Return whether the type of the specified range can precede the specified type.\r
-\r
- @param Ranges Memory range array holding memory type settings for all\r
- the memory address.\r
- @param RangeCount Count of memory ranges.\r
- @param Type Type to check precedence.\r
- @param SubBase Base address of the specified range.\r
- @param SubLength Length of the specified range.\r
-\r
- @retval TRUE The type of the specified range can precede the Type.\r
- @retval FALSE The type of the specified range cannot precede the Type.\r
- So the subtraction is not applicable.\r
-**/\r
-BOOLEAN\r
-MtrrLibSubstractable (\r
- IN CONST MEMORY_RANGE *Ranges,\r
- IN UINT32 RangeCount,\r
- IN MTRR_MEMORY_CACHE_TYPE Type,\r
- IN UINT64 SubBase,\r
- IN UINT64 SubLength\r
-)\r
-{\r
- UINT32 Index;\r
- UINT64 Length;\r
- // WT > WB\r
- // UC > *\r
- for (Index = 0; Index < RangeCount; Index++) {\r
- if (Ranges[Index].BaseAddress <= SubBase && SubBase < Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
-\r
- if (Ranges[Index].BaseAddress + Ranges[Index].Length >= SubBase + SubLength) {\r
- return MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type);\r
-\r
- } else {\r
- if (!MtrrLibTypeLeftPrecedeRight (Ranges[Index].Type, Type)) {\r
- return FALSE;\r
- }\r
-\r
- Length = Ranges[Index].BaseAddress + Ranges[Index].Length - SubBase;\r
- SubBase += Length;\r
- SubLength -= Length;\r
- }\r
- }\r
- }\r
-\r
- ASSERT (FALSE);\r
- return FALSE;\r
-}\r
-\r
-/**\r
- Return the number of required variable MTRRs to cover the specified range.\r
-\r
- The routine considers subtraction in the both side of the range to find out\r
- the most optimal solution (which uses the least MTRRs).\r
-\r
- @param Ranges Array holding memory type settings of all memory\r
- address.\r
- @param RangeCount Count of memory ranges.\r
- @param VariableMtrr Array holding allocated variable MTRRs.\r
- @param VariableMtrrCount Count of allocated variable MTRRs.\r
- @param BaseAddress Base address of the specified range.\r
- @param Length Length of the specified range.\r
- @param Type MTRR type of the specified range.\r
- @param Alignment0 Alignment of 0.\r
- @param SubLeft Return the count of left subtraction.\r
- @param SubRight Return the count of right subtraction.\r
-\r
- @return Number of required variable MTRRs.\r
-**/\r
-UINT32\r
-MtrrLibGetMtrrNumber (\r
- IN CONST MEMORY_RANGE *Ranges,\r
- IN UINT32 RangeCount,\r
- IN CONST VARIABLE_MTRR *VariableMtrr,\r
- IN UINT32 VariableMtrrCount,\r
- IN UINT64 BaseAddress,\r
- IN UINT64 Length,\r
- IN MTRR_MEMORY_CACHE_TYPE Type,\r
- IN UINT64 Alignment0,\r
- OUT UINT32 *SubLeft, // subtractive from BaseAddress to get more aligned address, to save MTRR\r
- OUT UINT32 *SubRight // subtractive from BaseAddress + Length, to save MTRR\r
- )\r
-{\r
- UINT64 Alignment;\r
- UINT32 LeastLeftMtrrNumber;\r
- UINT32 MiddleMtrrNumber;\r
- UINT32 LeastRightMtrrNumber;\r
- UINT32 CurrentMtrrNumber;\r
- UINT32 SubtractiveCount;\r
- UINT32 SubtractiveMtrrNumber;\r
- UINT32 LeastSubtractiveMtrrNumber;\r
- UINT64 SubtractiveBaseAddress;\r
- UINT64 SubtractiveLength;\r
- UINT64 BaseAlignment;\r
- UINT32 Index;\r
- UINT64 OriginalBaseAddress;\r
- UINT64 OriginalLength;\r
-\r
- *SubLeft = 0;\r
- *SubRight = 0;\r
- LeastSubtractiveMtrrNumber = 0;\r
- BaseAlignment = 0;\r
-\r
- //\r
- // Get the optimal left subtraction solution.\r
- //\r
- if (BaseAddress != 0) {\r
-\r
- OriginalBaseAddress = BaseAddress;\r
- OriginalLength = Length;\r
- SubtractiveBaseAddress = 0;\r
- SubtractiveLength = 0;\r
- //\r
- // Get the MTRR number needed without left subtraction.\r
- //\r
- LeastLeftMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
-\r
- //\r
- // Left subtraction bit by bit, to find the optimal left subtraction solution.\r
- //\r
- for (SubtractiveMtrrNumber = 0, SubtractiveCount = 1; BaseAddress != 0; SubtractiveCount++) {\r
- Alignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
-\r
- //\r
- // Check whether the memory type of [BaseAddress - Alignment, BaseAddress) can override Type.\r
- // IA32 Manual defines the following override rules:\r
- // WT > WB\r
- // UC > * (any)\r
- //\r
- if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress - Alignment, Alignment)) {\r
- break;\r
- }\r
-\r
- for (Index = 0; Index < VariableMtrrCount; Index++) {\r
- if ((VariableMtrr[Index].BaseAddress == BaseAddress - Alignment) &&\r
- (VariableMtrr[Index].Length == Alignment)) {\r
- break;\r
- }\r
- }\r
- if (Index == VariableMtrrCount) {\r
- //\r
- // Increment SubtractiveMtrrNumber when [BaseAddress - Alignment, BaseAddress) is not be planed as a MTRR\r
- //\r
- SubtractiveMtrrNumber++;\r
- }\r
-\r
- BaseAddress -= Alignment;\r
- Length += Alignment;\r
-\r
- CurrentMtrrNumber = SubtractiveMtrrNumber + MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
- if (CurrentMtrrNumber <= LeastLeftMtrrNumber) {\r
- LeastLeftMtrrNumber = CurrentMtrrNumber;\r
- LeastSubtractiveMtrrNumber = SubtractiveMtrrNumber;\r
- *SubLeft = SubtractiveCount;\r
- SubtractiveBaseAddress = BaseAddress;\r
- SubtractiveLength = Length;\r
- }\r
- }\r
-\r
- //\r
- // If left subtraction is better, subtract BaseAddress to left, and enlarge Length\r
- //\r
- if (*SubLeft != 0) {\r
- BaseAddress = SubtractiveBaseAddress;\r
- Length = SubtractiveLength;\r
- } else {\r
- BaseAddress = OriginalBaseAddress;\r
- Length = OriginalLength;\r
- }\r
- }\r
-\r
- //\r
- // Increment BaseAddress greedily until (BaseAddress + Alignment) exceeds (BaseAddress + Length)\r
- //\r
- MiddleMtrrNumber = 0;\r
- while (Length != 0) {\r
- BaseAlignment = MtrrLibLeastAlignment (BaseAddress, Alignment0);\r
- if (BaseAlignment > Length) {\r
- break;\r
- }\r
- BaseAddress += BaseAlignment;\r
- Length -= BaseAlignment;\r
- MiddleMtrrNumber++;\r
- }\r
-\r
-\r
- if (Length == 0) {\r
- return LeastSubtractiveMtrrNumber + MiddleMtrrNumber;\r
- }\r
-\r
-\r
- //\r
- // Get the optimal right subtraction solution.\r
- //\r
-\r
- //\r
- // Get the MTRR number needed without right subtraction.\r
- //\r
- LeastRightMtrrNumber = MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
-\r
- for (SubtractiveCount = 1; Length < BaseAlignment; SubtractiveCount++) {\r
- Alignment = MtrrLibLeastAlignment (BaseAddress + Length, Alignment0);\r
- if (!MtrrLibSubstractable (Ranges, RangeCount, Type, BaseAddress + Length, Alignment)) {\r
- break;\r
- }\r
-\r
- Length += Alignment;\r
-\r
- //\r
- // SubtractiveCount = Number of MTRRs used for subtraction\r
- //\r
- CurrentMtrrNumber = SubtractiveCount + MtrrLibGetPositiveMtrrNumber (BaseAddress, Length, Alignment0);\r
- if (CurrentMtrrNumber <= LeastRightMtrrNumber) {\r
- LeastRightMtrrNumber = CurrentMtrrNumber;\r
- *SubRight = SubtractiveCount;\r
- SubtractiveLength = Length;\r
- }\r
- }\r
-\r
- return LeastSubtractiveMtrrNumber + MiddleMtrrNumber + LeastRightMtrrNumber;\r
-}\r
-\r