+ If MtrrSetting is not NULL, print MTRR settings from input MTRR\r
+ settings buffer.\r
+ If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
+\r
+ @param MtrrSetting A buffer holding all MTRRs content.\r
+**/\r
+VOID\r
+MtrrDebugPrintAllMtrrsWorker (\r
+ IN MTRR_SETTINGS *MtrrSetting\r
+ )\r
+{\r
+ DEBUG_CODE (\r
+ MTRR_SETTINGS LocalMtrrs;\r
+ MTRR_SETTINGS *Mtrrs;\r
+ UINTN Index;\r
+ UINTN Index1;\r
+ UINTN VariableMtrrCount;\r
+ UINT64 Base;\r
+ UINT64 Limit;\r
+ UINT64 MtrrBase;\r
+ UINT64 MtrrLimit;\r
+ UINT64 RangeBase;\r
+ UINT64 RangeLimit;\r
+ UINT64 NoRangeBase;\r
+ UINT64 NoRangeLimit;\r
+ UINT32 RegEax;\r
+ UINTN MemoryType;\r
+ UINTN PreviousMemoryType;\r
+ BOOLEAN Found;\r
+\r
+ if (!IsMtrrSupported ()) {\r
+ return;\r
+ }\r
+\r
+ DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
+ DEBUG((DEBUG_CACHE, "=============\n"));\r
+\r
+ if (MtrrSetting != NULL) {\r
+ Mtrrs = MtrrSetting;\r
+ } else {\r
+ MtrrGetAllMtrrs (&LocalMtrrs);\r
+ Mtrrs = &LocalMtrrs;\r
+ }\r
+\r
+ DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+ DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
+ }\r
+\r
+ VariableMtrrCount = GetVariableMtrrCount ();\r
+ for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+ DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
+ Index,\r
+ Mtrrs->Variables.Mtrr[Index].Base,\r
+ Mtrrs->Variables.Mtrr[Index].Mask\r
+ ));\r
+ }\r
+ DEBUG((DEBUG_CACHE, "\n"));\r
+ DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
+ DEBUG((DEBUG_CACHE, "====================================\n"));\r
+\r
+ Base = 0;\r
+ PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+ Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
+ for (Index1 = 0; Index1 < 8; Index1++) {\r
+ MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
+ if (MemoryType > CacheWriteBack) {\r
+ MemoryType = MTRR_CACHE_INVALID_TYPE;\r
+ }\r
+ if (MemoryType != PreviousMemoryType) {\r
+ if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
+ DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
+ }\r
+ PreviousMemoryType = MemoryType;\r
+ DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
+ }\r
+ Base += mMtrrLibFixedMtrrTable[Index].Length;\r
+ }\r
+ }\r
+ DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
+\r
+ VariableMtrrCount = GetVariableMtrrCount ();\r
+\r
+ Limit = BIT36 - 1;\r
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+ if (RegEax >= 0x80000008) {\r
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+ Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
+ }\r
+ Base = BASE_1MB;\r
+ PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
+ do {\r
+ MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);\r
+ if (MemoryType > CacheWriteBack) {\r
+ MemoryType = MTRR_CACHE_INVALID_TYPE;\r
+ }\r
+\r
+ if (MemoryType != PreviousMemoryType) {\r
+ if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
+ DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
+ }\r
+ PreviousMemoryType = MemoryType;\r
+ DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
+ }\r
+\r
+ RangeBase = BASE_1MB;\r
+ NoRangeBase = BASE_1MB;\r
+ RangeLimit = Limit;\r
+ NoRangeLimit = Limit;\r
+\r
+ for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
+ if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
+ //\r
+ // If mask is not valid, then do not display range\r
+ //\r
+ continue;\r
+ }\r
+ MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
+ MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
+\r
+ if (Base >= MtrrBase && Base < MtrrLimit) {\r
+ Found = TRUE;\r
+ }\r
+\r
+ if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
+ RangeBase = MtrrBase;\r
+ }\r
+ if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
+ RangeBase = MtrrLimit + 1;\r
+ }\r
+ if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
+ RangeLimit = MtrrBase - 1;\r
+ }\r
+ if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
+ RangeLimit = MtrrLimit;\r
+ }\r
+\r
+ if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
+ NoRangeBase = MtrrLimit + 1;\r
+ }\r
+ if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
+ NoRangeLimit = MtrrBase - 1;\r
+ }\r
+ }\r
+\r
+ if (Found) {\r
+ Base = RangeLimit + 1;\r
+ } else {\r
+ Base = NoRangeLimit + 1;\r
+ }\r
+ } while (Base < Limit);\r
+ DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ This function prints all MTRRs for debugging.\r
+**/\r
+VOID\r
+EFIAPI\r
+MtrrDebugPrintAllMtrrs (\r
+ VOID\r
+ )\r
+{\r
+ MtrrDebugPrintAllMtrrsWorker (NULL);\r
+}\r
+\r
+/**\r
+ Update the Ranges array to change the specified range identified by\r
+ BaseAddress and Length to Type.\r
+\r
+ @param Ranges Array holding memory type settings for all memory regions.\r
+ @param Capacity The maximum count of memory ranges the array can hold.\r
+ @param Count Return the new memory range count in the array.\r
+ @param BaseAddress The base address of the memory range to change type.\r
+ @param Length The length of the memory range to change type.\r
+ @param Type The new type of the specified memory range.\r
+\r
+ @retval RETURN_SUCCESS The type of the specified memory range is\r
+ changed successfully.\r
+ @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory\r
+ range exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibSetMemoryType (\r
+ IN MEMORY_RANGE *Ranges,\r
+ IN UINT32 Capacity,\r
+ IN OUT UINT32 *Count,\r
+ IN UINT64 BaseAddress,\r
+ IN UINT64 Length,\r
+ IN MTRR_MEMORY_CACHE_TYPE Type\r
+ )\r
+{\r
+ UINT32 Index;\r
+ UINT64 Limit;\r
+ UINT64 LengthLeft;\r
+ UINT64 LengthRight;\r
+ UINT32 StartIndex;\r
+ UINT32 EndIndex;\r
+ UINT32 DeltaCount;\r
+\r
+ LengthRight = 0;\r
+ LengthLeft = 0;\r
+ Limit = BaseAddress + Length;\r
+ StartIndex = *Count;\r
+ EndIndex = *Count;\r
+ for (Index = 0; Index < *Count; Index++) {\r
+ if ((StartIndex == *Count) &&\r
+ (Ranges[Index].BaseAddress <= BaseAddress) &&\r
+ (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
+ StartIndex = Index;\r
+ LengthLeft = BaseAddress - Ranges[Index].BaseAddress;\r
+ }\r
+\r
+ if ((EndIndex == *Count) &&\r
+ (Ranges[Index].BaseAddress < Limit) &&\r
+ (Limit <= Ranges[Index].BaseAddress + Ranges[Index].Length)) {\r
+ EndIndex = Index;\r
+ LengthRight = Ranges[Index].BaseAddress + Ranges[Index].Length - Limit;\r
+ break;\r
+ }\r
+ }\r
+\r
+ ASSERT (StartIndex != *Count && EndIndex != *Count);\r
+ if (StartIndex == EndIndex && Ranges[StartIndex].Type == Type) {\r
+ return RETURN_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // The type change may cause merging with previous range or next range.\r
+ // Update the StartIndex, EndIndex, BaseAddress, Length so that following\r
+ // logic doesn't need to consider merging.\r
+ //\r
+ if (StartIndex != 0) {\r
+ if (LengthLeft == 0 && Ranges[StartIndex - 1].Type == Type) {\r
+ StartIndex--;\r
+ Length += Ranges[StartIndex].Length;\r
+ BaseAddress -= Ranges[StartIndex].Length;\r
+ }\r
+ }\r
+ if (EndIndex != (*Count) - 1) {\r
+ if (LengthRight == 0 && Ranges[EndIndex + 1].Type == Type) {\r
+ EndIndex++;\r
+ Length += Ranges[EndIndex].Length;\r
+ }\r
+ }\r
+\r
+ //\r
+ // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)\r
+ // |++++++++++++++++++| 0 3 1=3-0-2 3\r
+ // |+++++++| 0 1 -1=1-0-2 5\r
+ // |+| 0 0 -2=0-0-2 6\r
+ // |+++| 0 0 -1=0-0-2+1 5\r
+ //\r
+ //\r
+ DeltaCount = EndIndex - StartIndex - 2;\r
+ if (LengthLeft == 0) {\r
+ DeltaCount++;\r
+ }\r
+ if (LengthRight == 0) {\r
+ DeltaCount++;\r
+ }\r
+ if (*Count - DeltaCount > Capacity) {\r
+ return RETURN_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Reserve (-DeltaCount) space\r
+ //\r
+ CopyMem (&Ranges[EndIndex + 1 - DeltaCount], &Ranges[EndIndex + 1], (*Count - EndIndex - 1) * sizeof (Ranges[0]));\r
+ *Count -= DeltaCount;\r
+\r
+ 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