+MtrrLibSetMemoryRanges (\r
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
+ IN UINT64 A0,\r
+ IN MTRR_MEMORY_RANGE *Ranges,\r
+ IN UINTN RangeCount,\r
+ IN VOID *Scratch,\r
+ IN OUT UINTN *ScratchSize,\r
+ OUT MTRR_MEMORY_RANGE *VariableMtrr,\r
+ IN UINT32 VariableMtrrCapacity,\r
+ OUT UINT32 *VariableMtrrCount\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ UINT32 Index;\r
+ UINT64 Base0;\r
+ UINT64 Base1;\r
+ UINT64 Alignment;\r
+ UINT8 CompatibleTypes;\r
+ UINT64 Length;\r
+ UINT32 End;\r
+ UINTN ActualScratchSize;\r
+ UINTN BiggestScratchSize;\r
+\r
+ *VariableMtrrCount = 0;\r
+ \r
+ //\r
+ // Since the whole ranges need multiple calls of MtrrLibCalculateMtrrs().\r
+ // Each call needs different scratch buffer size.\r
+ // When the provided scratch buffer size is not sufficient in any call,\r
+ // set the GetActualScratchSize to TRUE, and following calls will only\r
+ // calculate the actual scratch size for the caller.\r
+ //\r
+ BiggestScratchSize = 0;\r
+\r
+ for (Index = 0; Index < RangeCount;) {\r
+ Base0 = Ranges[Index].BaseAddress;\r
+\r
+ //\r
+ // Full step is optimal\r
+ //\r
+ while (Index < RangeCount) {\r
+ ASSERT (Ranges[Index].BaseAddress == Base0);\r
+ Alignment = MtrrLibBiggestAlignment (Base0, A0);\r
+ while (Base0 + Alignment <= Ranges[Index].BaseAddress + Ranges[Index].Length) {\r
+ if ((BiggestScratchSize <= *ScratchSize) && (Ranges[Index].Type != DefaultType)) {\r
+ Status = MtrrLibAppendVariableMtrr (\r
+ VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,\r
+ Base0, Alignment, Ranges[Index].Type\r
+ );\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ Base0 += Alignment;\r
+ Alignment = MtrrLibBiggestAlignment (Base0, A0);\r
+ }\r
+\r
+ //\r
+ // Remove the above range from Ranges[Index]\r
+ //\r
+ Ranges[Index].Length -= Base0 - Ranges[Index].BaseAddress;\r
+ Ranges[Index].BaseAddress = Base0;\r
+ if (Ranges[Index].Length != 0) {\r
+ break;\r
+ } else {\r
+ Index++;\r
+ }\r
+ }\r
+\r
+ if (Index == RangeCount) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Find continous ranges [Base0, Base1) which could be combined by MTRR.\r
+ // Per SDM, the compatible types between[B0, B1) are:\r
+ // UC, *\r
+ // WB, WT\r
+ // UC, WB, WT\r
+ //\r
+ CompatibleTypes = MtrrLibGetCompatibleTypes (&Ranges[Index], RangeCount - Index);\r
+\r
+ End = Index; // End points to last one that matches the CompatibleTypes.\r
+ while (End + 1 < RangeCount) {\r
+ if (((1 << Ranges[End + 1].Type) & CompatibleTypes) == 0) {\r
+ break;\r
+ }\r
+ End++;\r
+ }\r
+ Alignment = MtrrLibBiggestAlignment (Base0, A0);\r
+ Length = GetPowerOfTwo64 (Ranges[End].BaseAddress + Ranges[End].Length - Base0);\r
+ Base1 = Base0 + MIN (Alignment, Length);\r
+\r
+ //\r
+ // Base1 may not in Ranges[End]. Update End to the range Base1 belongs to.\r
+ //\r
+ End = Index;\r
+ while (End + 1 < RangeCount) {\r
+ if (Base1 <= Ranges[End + 1].BaseAddress) {\r
+ break;\r
+ }\r
+ End++;\r
+ }\r
+\r
+ Length = Ranges[End].Length;\r
+ Ranges[End].Length = Base1 - Ranges[End].BaseAddress;\r
+ ActualScratchSize = *ScratchSize;\r
+ Status = MtrrLibCalculateMtrrs (\r
+ DefaultType, A0,\r
+ &Ranges[Index], End + 1 - Index,\r
+ Scratch, &ActualScratchSize,\r
+ VariableMtrr, VariableMtrrCapacity, VariableMtrrCount\r
+ );\r
+ if (Status == RETURN_BUFFER_TOO_SMALL) {\r
+ BiggestScratchSize = MAX (BiggestScratchSize, ActualScratchSize);\r
+ //\r
+ // Ignore this error, because we need to calculate the biggest\r
+ // scratch buffer size.\r
+ //\r
+ Status = RETURN_SUCCESS;\r
+ }\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Length != Ranges[End].Length) {\r
+ Ranges[End].BaseAddress = Base1;\r
+ Ranges[End].Length = Length - Ranges[End].Length;\r
+ Index = End;\r
+ } else {\r
+ Index = End + 1;\r
+ }\r
+ }\r
+\r
+ if (*ScratchSize < BiggestScratchSize) {\r
+ *ScratchSize = BiggestScratchSize;\r
+ return RETURN_BUFFER_TOO_SMALL;\r
+ }\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+ Set the below-1MB memory attribute to fixed MTRR buffer.\r
+ Modified flag array indicates which fixed MTRR is modified.\r
+\r
+ @param [in, out] FixedSettings Fixed MTRR buffer.\r
+ @param [out] Modified Flag array indicating which MTRR is modified.\r
+ @param [in] BaseAddress Base address.\r
+ @param [in] Length Length.\r
+ @param [in] Type Memory type.\r
+\r
+ @retval RETURN_SUCCESS The memory attribute is set successfully.\r
+ @retval RETURN_UNSUPPORTED The requested range or cache type was invalid\r
+ for the fixed MTRRs.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibSetBelow1MBMemoryAttribute (\r
+ IN OUT MTRR_FIXED_SETTINGS *FixedSettings,\r
+ OUT BOOLEAN *Modified,\r