--- /dev/null
+/** @file\r
+ Unit tests of the MtrrLib instance of the MtrrLib class\r
+\r
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "MtrrLibUnitTest.h"\r
+\r
+STATIC CONST MTRR_LIB_SYSTEM_PARAMETER mDefaultSystemParameter = {\r
+ 42, TRUE, TRUE, CacheUncacheable, 12\r
+};\r
+\r
+STATIC MTRR_LIB_SYSTEM_PARAMETER mSystemParameters[] = {\r
+ { 38, TRUE, TRUE, CacheUncacheable, 12 },\r
+ { 38, TRUE, TRUE, CacheWriteBack, 12 },\r
+ { 38, TRUE, TRUE, CacheWriteThrough, 12 },\r
+ { 38, TRUE, TRUE, CacheWriteProtected, 12 },\r
+ { 38, TRUE, TRUE, CacheWriteCombining, 12 },\r
+\r
+ { 42, TRUE, TRUE, CacheUncacheable, 12 },\r
+ { 42, TRUE, TRUE, CacheWriteBack, 12 },\r
+ { 42, TRUE, TRUE, CacheWriteThrough, 12 },\r
+ { 42, TRUE, TRUE, CacheWriteProtected, 12 },\r
+ { 42, TRUE, TRUE, CacheWriteCombining, 12 },\r
+\r
+ { 48, TRUE, TRUE, CacheUncacheable, 12 },\r
+ { 48, TRUE, TRUE, CacheWriteBack, 12 },\r
+ { 48, TRUE, TRUE, CacheWriteThrough, 12 },\r
+ { 48, TRUE, TRUE, CacheWriteProtected, 12 },\r
+ { 48, TRUE, TRUE, CacheWriteCombining, 12 },\r
+};\r
+\r
+UINT32 mFixedMtrrsIndex[] = {\r
+ MSR_IA32_MTRR_FIX64K_00000,\r
+ MSR_IA32_MTRR_FIX16K_80000,\r
+ MSR_IA32_MTRR_FIX16K_A0000,\r
+ MSR_IA32_MTRR_FIX4K_C0000,\r
+ MSR_IA32_MTRR_FIX4K_C8000,\r
+ MSR_IA32_MTRR_FIX4K_D0000,\r
+ MSR_IA32_MTRR_FIX4K_D8000,\r
+ MSR_IA32_MTRR_FIX4K_E0000,\r
+ MSR_IA32_MTRR_FIX4K_E8000,\r
+ MSR_IA32_MTRR_FIX4K_F0000,\r
+ MSR_IA32_MTRR_FIX4K_F8000\r
+};\r
+STATIC_ASSERT (\r
+ (ARRAY_SIZE (mFixedMtrrsIndex) == MTRR_NUMBER_OF_FIXED_MTRR),\r
+ "gFixedMtrrIndex does NOT contain all the fixed MTRRs!"\r
+ );\r
+\r
+//\r
+// Context structure to be used for most of the test cases.\r
+//\r
+typedef struct {\r
+ CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter;\r
+} MTRR_LIB_TEST_CONTEXT;\r
+\r
+//\r
+// Context structure to be used for GetFirmwareVariableMtrrCount() test.\r
+//\r
+typedef struct {\r
+ UINT32 NumberOfReservedVariableMtrrs;\r
+ CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter;\r
+} MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT;\r
+\r
+STATIC CHAR8 *mCacheDescription[] = { "UC", "WC", "N/A", "N/A", "WT", "WP", "WB" };\r
+\r
+/**\r
+ Compare the actual memory ranges against expected memory ranges and return PASS when they match.\r
+\r
+ @param ExpectedMemoryRanges Expected memory ranges.\r
+ @param ExpectedMemoryRangeCount Count of expected memory ranges.\r
+ @param ActualRanges Actual memory ranges.\r
+ @param ActualRangeCount Count of actual memory ranges.\r
+\r
+ @retval UNIT_TEST_PASSED Test passed.\r
+ @retval others Test failed.\r
+**/\r
+UNIT_TEST_STATUS\r
+VerifyMemoryRanges (\r
+ IN MTRR_MEMORY_RANGE *ExpectedMemoryRanges,\r
+ IN UINTN ExpectedMemoryRangeCount,\r
+ IN MTRR_MEMORY_RANGE *ActualRanges,\r
+ IN UINTN ActualRangeCount\r
+ )\r
+{\r
+ UINTN Index;\r
+ UT_ASSERT_EQUAL (ExpectedMemoryRangeCount, ActualRangeCount);\r
+ for (Index = 0; Index < ExpectedMemoryRangeCount; Index++) {\r
+ UT_ASSERT_EQUAL (ExpectedMemoryRanges[Index].BaseAddress, ActualRanges[Index].BaseAddress);\r
+ UT_ASSERT_EQUAL (ExpectedMemoryRanges[Index].Length, ActualRanges[Index].Length);\r
+ UT_ASSERT_EQUAL (ExpectedMemoryRanges[Index].Type, ActualRanges[Index].Type);\r
+ }\r
+\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Dump the memory ranges.\r
+\r
+ @param Ranges Memory ranges to dump.\r
+ @param RangeCount Count of memory ranges.\r
+**/\r
+VOID\r
+DumpMemoryRanges (\r
+ MTRR_MEMORY_RANGE *Ranges,\r
+ UINTN RangeCount\r
+ )\r
+{\r
+ UINTN Index;\r
+ for (Index = 0; Index < RangeCount; Index++) {\r
+ UT_LOG_INFO ("\t{ 0x%016llx, 0x%016llx, %a },\n", Ranges[Index].BaseAddress, Ranges[Index].Length, mCacheDescription[Ranges[Index].Type]);\r
+ }\r
+}\r
+\r
+/**\r
+**/\r
+\r
+/**\r
+ Generate random count of MTRRs for each cache type.\r
+\r
+ @param TotalCount Total MTRR count.\r
+ @param UcCount Return count of Uncacheable type.\r
+ @param WtCount Return count of Write Through type.\r
+ @param WbCount Return count of Write Back type.\r
+ @param WpCount Return count of Write Protected type.\r
+ @param WcCount Return count of Write Combining type.\r
+**/\r
+VOID\r
+GenerateRandomMemoryTypeCombination (\r
+ IN UINT32 TotalCount,\r
+ OUT UINT32 *UcCount,\r
+ OUT UINT32 *WtCount,\r
+ OUT UINT32 *WbCount,\r
+ OUT UINT32 *WpCount,\r
+ OUT UINT32 *WcCount\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINT32 TotalMtrrCount;\r
+ UINT32 *CountPerType[5];\r
+\r
+ CountPerType[0] = UcCount;\r
+ CountPerType[1] = WtCount;\r
+ CountPerType[2] = WbCount;\r
+ CountPerType[3] = WpCount;\r
+ CountPerType[4] = WcCount;\r
+\r
+ //\r
+ // Initialize the count of each cache type to 0.\r
+ //\r
+ for (Index = 0; Index < ARRAY_SIZE (CountPerType); Index++) {\r
+ *(CountPerType[Index]) = 0;\r
+ }\r
+\r
+ //\r
+ // Pick a random count of MTRRs\r
+ //\r
+ TotalMtrrCount = Random32 (1, TotalCount);\r
+ for (Index = 0; Index < TotalMtrrCount; Index++) {\r
+ //\r
+ // For each of them, pick a random cache type.\r
+ //\r
+ (*(CountPerType[Random32 (0, ARRAY_SIZE (CountPerType) - 1)]))++;\r
+ }\r
+}\r
+\r
+/**\r
+ Unit test of MtrrLib service MtrrSetMemoryAttribute()\r
+\r
+ @param[in] Context Ignored\r
+\r
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test\r
+ case was successful.\r
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.\r
+\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+UnitTestMtrrSetMemoryAttributesInMtrrSettings (\r
+ IN UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter;\r
+ RETURN_STATUS Status;\r
+ UINT32 UcCount;\r
+ UINT32 WtCount;\r
+ UINT32 WbCount;\r
+ UINT32 WpCount;\r
+ UINT32 WcCount;\r
+\r
+ UINT32 MtrrIndex;\r
+ UINT8 *Scratch;\r
+ UINTN ScratchSize;\r
+ MTRR_SETTINGS LocalMtrrs;\r
+\r
+ MTRR_MEMORY_RANGE RawMtrrRange[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+ MTRR_MEMORY_RANGE ExpectedMemoryRanges[MTRR_NUMBER_OF_FIXED_MTRR * sizeof (UINT64) + 2 * MTRR_NUMBER_OF_VARIABLE_MTRR + 1];\r
+ UINT32 ExpectedVariableMtrrUsage;\r
+ UINTN ExpectedMemoryRangesCount;\r
+\r
+ MTRR_MEMORY_RANGE ActualMemoryRanges[MTRR_NUMBER_OF_FIXED_MTRR * sizeof (UINT64) + 2 * MTRR_NUMBER_OF_VARIABLE_MTRR + 1];\r
+ UINT32 ActualVariableMtrrUsage;\r
+ UINTN ActualMemoryRangesCount;\r
+\r
+ MTRR_SETTINGS *Mtrrs[2];\r
+\r
+ SystemParameter = (MTRR_LIB_SYSTEM_PARAMETER *) Context;\r
+ GenerateRandomMemoryTypeCombination (\r
+ SystemParameter->VariableMtrrCount - PatchPcdGet32 (PcdCpuNumberOfReservedVariableMtrrs),\r
+ &UcCount, &WtCount, &WbCount, &WpCount, &WcCount\r
+ );\r
+ GenerateValidAndConfigurableMtrrPairs (\r
+ SystemParameter->PhysicalAddressBits, RawMtrrRange,\r
+ UcCount, WtCount, WbCount, WpCount, WcCount\r
+ );\r
+\r
+ ExpectedVariableMtrrUsage = UcCount + WtCount + WbCount + WpCount + WcCount;\r
+ ExpectedMemoryRangesCount = ARRAY_SIZE (ExpectedMemoryRanges);\r
+ GetEffectiveMemoryRanges (\r
+ SystemParameter->DefaultCacheType,\r
+ SystemParameter->PhysicalAddressBits,\r
+ RawMtrrRange, ExpectedVariableMtrrUsage,\r
+ ExpectedMemoryRanges, &ExpectedMemoryRangesCount\r
+ );\r
+\r
+ UT_LOG_INFO (\r
+ "Total MTRR [%d]: UC=%d, WT=%d, WB=%d, WP=%d, WC=%d\n",\r
+ ExpectedVariableMtrrUsage, UcCount, WtCount, WbCount, WpCount, WcCount\r
+ );\r
+ UT_LOG_INFO ("--- Expected Memory Ranges [%d] ---\n", ExpectedMemoryRangesCount);\r
+ DumpMemoryRanges (ExpectedMemoryRanges, ExpectedMemoryRangesCount);\r
+\r
+ //\r
+ // Default cache type is always an INPUT\r
+ //\r
+ ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs));\r
+ LocalMtrrs.MtrrDefType = MtrrGetDefaultMemoryType ();\r
+ ScratchSize = SCRATCH_BUFFER_SIZE;\r
+ Mtrrs[0] = &LocalMtrrs;\r
+ Mtrrs[1] = NULL;\r
+\r
+ for (MtrrIndex = 0; MtrrIndex < ARRAY_SIZE (Mtrrs); MtrrIndex++) {\r
+ Scratch = calloc (ScratchSize, sizeof (UINT8));\r
+ Status = MtrrSetMemoryAttributesInMtrrSettings (Mtrrs[MtrrIndex], Scratch, &ScratchSize, ExpectedMemoryRanges, ExpectedMemoryRangesCount);\r
+ if (Status == RETURN_BUFFER_TOO_SMALL) {\r
+ Scratch = realloc (Scratch, ScratchSize);\r
+ Status = MtrrSetMemoryAttributesInMtrrSettings (Mtrrs[MtrrIndex], Scratch, &ScratchSize, ExpectedMemoryRanges, ExpectedMemoryRangesCount);\r
+ }\r
+ UT_ASSERT_STATUS_EQUAL (Status, RETURN_SUCCESS);\r
+\r
+ if (Mtrrs[MtrrIndex] == NULL) {\r
+ ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs));\r
+ MtrrGetAllMtrrs (&LocalMtrrs);\r
+ }\r
+ ActualMemoryRangesCount = ARRAY_SIZE (ActualMemoryRanges);\r
+ CollectTestResult (\r
+ SystemParameter->DefaultCacheType, SystemParameter->PhysicalAddressBits, SystemParameter->VariableMtrrCount,\r
+ &LocalMtrrs, ActualMemoryRanges, &ActualMemoryRangesCount, &ActualVariableMtrrUsage\r
+ );\r
+\r
+ UT_LOG_INFO ("--- Actual Memory Ranges [%d] ---\n", ActualMemoryRangesCount);\r
+ DumpMemoryRanges (ActualMemoryRanges, ActualMemoryRangesCount);\r
+ VerifyMemoryRanges (ExpectedMemoryRanges, ExpectedMemoryRangesCount, ActualMemoryRanges, ActualMemoryRangesCount);\r
+ UT_ASSERT_TRUE (ExpectedVariableMtrrUsage >= ActualVariableMtrrUsage);\r
+\r
+ ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs));\r
+ }\r
+\r
+ free (Scratch);\r
+\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Test routine to check whether invalid base/size can be rejected.\r
+\r
+ @param Context Pointer to MTRR_LIB_SYSTEM_PARAMETER.\r
+\r
+ @return Test status.\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+UnitTestInvalidMemoryLayouts (\r
+ IN UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter;\r
+ MTRR_MEMORY_RANGE Ranges[MTRR_NUMBER_OF_VARIABLE_MTRR * 2 + 1];\r
+ UINTN RangeCount;\r
+ UINT64 MaxAddress;\r
+ UINT32 Index;\r
+ UINT64 BaseAddress;\r
+ UINT64 Length;\r
+ RETURN_STATUS Status;\r
+ UINTN ScratchSize;\r
+\r
+ SystemParameter = (MTRR_LIB_SYSTEM_PARAMETER *) Context;\r
+\r
+ RangeCount = Random32 (1, ARRAY_SIZE (Ranges));\r
+ MaxAddress = 1ull << SystemParameter->PhysicalAddressBits;\r
+\r
+ for (Index = 0; Index < RangeCount; Index++) {\r
+ do {\r
+ BaseAddress = Random64 (0, MaxAddress);\r
+ Length = Random64 (1, MaxAddress - BaseAddress);\r
+ } while (((BaseAddress & 0xFFF) == 0) || ((Length & 0xFFF) == 0));\r
+\r
+ Ranges[Index].BaseAddress = BaseAddress;\r
+ Ranges[Index].Length = Length;\r
+ Ranges[Index].Type = GenerateRandomCacheType ();\r
+\r
+ Status = MtrrSetMemoryAttribute (\r
+ Ranges[Index].BaseAddress, Ranges[Index].Length, Ranges[Index].Type\r
+ );\r
+ UT_ASSERT_TRUE (RETURN_ERROR (Status));\r
+ }\r
+\r
+ ScratchSize = 0;\r
+ Status = MtrrSetMemoryAttributesInMtrrSettings (NULL, NULL, &ScratchSize, Ranges, RangeCount);\r
+ UT_ASSERT_TRUE (RETURN_ERROR (Status));\r
+\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Unit test of MtrrLib service IsMtrrSupported()\r
+\r
+ @param[in] Context Ignored\r
+\r
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test\r
+ case was successful.\r
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.\r
+\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+UnitTestIsMtrrSupported (\r
+ IN UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;\r
+ MTRR_LIB_TEST_CONTEXT *LocalContext;\r
+\r
+ LocalContext = (MTRR_LIB_TEST_CONTEXT *) Context;\r
+\r
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));\r
+ //\r
+ // MTRR capability off in CPUID leaf.\r
+ //\r
+ SystemParameter.MtrrSupported = FALSE;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ UT_ASSERT_FALSE (IsMtrrSupported ());\r
+\r
+ //\r
+ // MTRR capability on in CPUID leaf, but no variable or fixed MTRRs.\r
+ //\r
+ SystemParameter.MtrrSupported = TRUE;\r
+ SystemParameter.VariableMtrrCount = 0;\r
+ SystemParameter.FixedMtrrSupported = FALSE;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ UT_ASSERT_FALSE (IsMtrrSupported ());\r
+\r
+ //\r
+ // MTRR capability on in CPUID leaf, but no variable MTRRs.\r
+ //\r
+ SystemParameter.MtrrSupported = TRUE;\r
+ SystemParameter.VariableMtrrCount = 0;\r
+ SystemParameter.FixedMtrrSupported = TRUE;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ UT_ASSERT_FALSE (IsMtrrSupported ());\r
+\r
+ //\r
+ // MTRR capability on in CPUID leaf, but no fixed MTRRs.\r
+ //\r
+ SystemParameter.MtrrSupported = TRUE;\r
+ SystemParameter.VariableMtrrCount = 7;\r
+ SystemParameter.FixedMtrrSupported = FALSE;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ UT_ASSERT_FALSE (IsMtrrSupported ());\r
+\r
+ //\r
+ // MTRR capability on in CPUID leaf with both variable and fixed MTRRs.\r
+ //\r
+ SystemParameter.MtrrSupported = TRUE;\r
+ SystemParameter.VariableMtrrCount = 7;\r
+ SystemParameter.FixedMtrrSupported = TRUE;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ UT_ASSERT_TRUE (IsMtrrSupported ());\r
+\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Unit test of MtrrLib service GetVariableMtrrCount()\r
+\r
+ @param[in] Context Ignored\r
+\r
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test\r
+ case was successful.\r
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.\r
+\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+UnitTestGetVariableMtrrCount (\r
+ IN UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ UINT32 Result;\r
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;\r
+ MTRR_LIB_TEST_CONTEXT *LocalContext;\r
+\r
+ LocalContext = (MTRR_LIB_TEST_CONTEXT *) Context;\r
+\r
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));\r
+ //\r
+ // If MTRR capability off in CPUID leaf, then the count is always 0.\r
+ //\r
+ SystemParameter.MtrrSupported = FALSE;\r
+ for (SystemParameter.VariableMtrrCount = 1; SystemParameter.VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR; SystemParameter.VariableMtrrCount++) {\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ Result = GetVariableMtrrCount ();\r
+ UT_ASSERT_EQUAL (Result, 0);\r
+ }\r
+\r
+ //\r
+ // Try all supported variable MTRR counts.\r
+ // If variable MTRR count is > MTRR_NUMBER_OF_VARIABLE_MTRR, then an ASSERT()\r
+ // is generated.\r
+ //\r
+ SystemParameter.MtrrSupported = TRUE;\r
+ for (SystemParameter.VariableMtrrCount = 1; SystemParameter.VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR; SystemParameter.VariableMtrrCount++) {\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ Result = GetVariableMtrrCount ();\r
+ UT_ASSERT_EQUAL (Result, SystemParameter.VariableMtrrCount);\r
+ }\r
+\r
+ //\r
+ // Expect ASSERT() if variable MTRR count is > MTRR_NUMBER_OF_VARIABLE_MTRR\r
+ //\r
+ SystemParameter.VariableMtrrCount = MTRR_NUMBER_OF_VARIABLE_MTRR + 1;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ UT_EXPECT_ASSERT_FAILURE (GetVariableMtrrCount (), NULL);\r
+\r
+ SystemParameter.MtrrSupported = TRUE;\r
+ SystemParameter.VariableMtrrCount = MAX_UINT8;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ UT_EXPECT_ASSERT_FAILURE (GetVariableMtrrCount (), NULL);\r
+\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Unit test of MtrrLib service GetFirmwareVariableMtrrCount()\r
+\r
+ @param[in] Context Ignored\r
+\r
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test\r
+ case was successful.\r
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.\r
+\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+UnitTestGetFirmwareVariableMtrrCount (\r
+ IN UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ UINT32 Result;\r
+ UINT32 ReservedMtrrs;\r
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;\r
+ MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *LocalContext;\r
+\r
+ LocalContext = (MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *) Context;\r
+\r
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));\r
+\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ //\r
+ // Positive test cases for VCNT = 10 and Reserved PCD in range 0..10\r
+ //\r
+ for (ReservedMtrrs = 0; ReservedMtrrs <= SystemParameter.VariableMtrrCount; ReservedMtrrs++) {\r
+ PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, ReservedMtrrs);\r
+ Result = GetFirmwareVariableMtrrCount ();\r
+ UT_ASSERT_EQUAL (Result, SystemParameter.VariableMtrrCount - ReservedMtrrs);\r
+ }\r
+\r
+ //\r
+ // Negative test cases when Reserved PCD is larger than VCNT\r
+ //\r
+ for (ReservedMtrrs = SystemParameter.VariableMtrrCount + 1; ReservedMtrrs <= 255; ReservedMtrrs++) {\r
+ PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, ReservedMtrrs);\r
+ Result = GetFirmwareVariableMtrrCount ();\r
+ UT_ASSERT_EQUAL (Result, 0);\r
+ }\r
+\r
+ //\r
+ // Negative test cases when Reserved PCD is larger than VCNT\r
+ //\r
+ PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, MAX_UINT32);\r
+ Result = GetFirmwareVariableMtrrCount ();\r
+ UT_ASSERT_EQUAL (Result, 0);\r
+\r
+ //\r
+ // Negative test case when MTRRs are not supported\r
+ //\r
+ SystemParameter.MtrrSupported = FALSE;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, 2);\r
+ Result = GetFirmwareVariableMtrrCount ();\r
+ UT_ASSERT_EQUAL (Result, 0);\r
+\r
+ //\r
+ // Negative test case when Fixed MTRRs are not supported\r
+ //\r
+ SystemParameter.MtrrSupported = TRUE;\r
+ SystemParameter.FixedMtrrSupported = FALSE;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, 2);\r
+ Result = GetFirmwareVariableMtrrCount ();\r
+ UT_ASSERT_EQUAL (Result, 0);\r
+\r
+ //\r
+ // Expect ASSERT() if variable MTRR count is > MTRR_NUMBER_OF_VARIABLE_MTRR\r
+ //\r
+ SystemParameter.FixedMtrrSupported = TRUE;\r
+ SystemParameter.VariableMtrrCount = MTRR_NUMBER_OF_VARIABLE_MTRR + 1;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ UT_EXPECT_ASSERT_FAILURE (GetFirmwareVariableMtrrCount (), NULL);\r
+\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Unit test of MtrrLib service MtrrGetMemoryAttribute()\r
+\r
+ @param[in] Context Ignored\r
+\r
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test\r
+ case was successful.\r
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.\r
+\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+UnitTestMtrrGetMemoryAttribute (\r
+ IN UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Unit test of MtrrLib service MtrrGetFixedMtrr()\r
+\r
+ @param[in] Context Ignored\r
+\r
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test\r
+ case was successful.\r
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.\r
+\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+UnitTestMtrrGetFixedMtrr (\r
+ IN UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ MTRR_FIXED_SETTINGS *Result;\r
+ MTRR_FIXED_SETTINGS ExpectedFixedSettings;\r
+ MTRR_FIXED_SETTINGS FixedSettings;\r
+ UINTN Index;\r
+ UINTN MsrIndex;\r
+ UINTN ByteIndex;\r
+ UINT64 MsrValue;\r
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;\r
+ MTRR_LIB_TEST_CONTEXT *LocalContext;\r
+\r
+ LocalContext = (MTRR_LIB_TEST_CONTEXT *) Context;\r
+\r
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ //\r
+ // Set random cache type to different ranges under 1MB and make sure\r
+ // the fixed MTRR settings are expected.\r
+ // Try 100 times.\r
+ //\r
+ for (Index = 0; Index < 100; Index++) {\r
+ for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mFixedMtrrsIndex); MsrIndex++) {\r
+ MsrValue = 0;\r
+ for (ByteIndex = 0; ByteIndex < sizeof (UINT64); ByteIndex++) {\r
+ MsrValue = MsrValue | LShiftU64 (GenerateRandomCacheType (), ByteIndex * 8);\r
+ }\r
+ ExpectedFixedSettings.Mtrr[MsrIndex] = MsrValue;\r
+ AsmWriteMsr64 (mFixedMtrrsIndex[MsrIndex], MsrValue);\r
+ }\r
+\r
+ Result = MtrrGetFixedMtrr (&FixedSettings);\r
+ UT_ASSERT_EQUAL (Result, &FixedSettings);\r
+ UT_ASSERT_MEM_EQUAL (&FixedSettings, &ExpectedFixedSettings, sizeof (FixedSettings));\r
+ }\r
+\r
+ //\r
+ // Negative test case when MTRRs are not supported\r
+ //\r
+ SystemParameter.MtrrSupported = FALSE;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+\r
+ ZeroMem (&FixedSettings, sizeof (FixedSettings));\r
+ ZeroMem (&ExpectedFixedSettings, sizeof (ExpectedFixedSettings));\r
+ Result = MtrrGetFixedMtrr (&FixedSettings);\r
+ UT_ASSERT_EQUAL (Result, &FixedSettings);\r
+ UT_ASSERT_MEM_EQUAL (&ExpectedFixedSettings, &FixedSettings, sizeof (ExpectedFixedSettings));\r
+\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Unit test of MtrrLib service MtrrGetAllMtrrs()\r
+\r
+ @param[in] Context Ignored\r
+\r
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test\r
+ case was successful.\r
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.\r
+\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+UnitTestMtrrGetAllMtrrs (\r
+ IN UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ MTRR_SETTINGS *Result;\r
+ MTRR_SETTINGS Mtrrs;\r
+ MTRR_SETTINGS ExpectedMtrrs;\r
+ MTRR_VARIABLE_SETTING VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+ UINT32 Index;\r
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;\r
+ MTRR_LIB_TEST_CONTEXT *LocalContext;\r
+\r
+ LocalContext = (MTRR_LIB_TEST_CONTEXT *) Context;\r
+\r
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));\r
+ InitializeMtrrRegs (&SystemParameter);\r
+\r
+ for (Index = 0; Index < SystemParameter.VariableMtrrCount; Index++) {\r
+ GenerateRandomMtrrPair (SystemParameter.PhysicalAddressBits, GenerateRandomCacheType (), &VariableMtrr[Index], NULL);\r
+ AsmWriteMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1), VariableMtrr[Index].Base);\r
+ AsmWriteMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1), VariableMtrr[Index].Mask);\r
+ }\r
+ Result = MtrrGetAllMtrrs (&Mtrrs);\r
+ UT_ASSERT_EQUAL (Result, &Mtrrs);\r
+ UT_ASSERT_MEM_EQUAL (Mtrrs.Variables.Mtrr, VariableMtrr, sizeof (MTRR_VARIABLE_SETTING) * SystemParameter.VariableMtrrCount);\r
+\r
+ //\r
+ // Negative test case when MTRRs are not supported\r
+ //\r
+ ZeroMem (&ExpectedMtrrs, sizeof (ExpectedMtrrs));\r
+ ZeroMem (&Mtrrs, sizeof (Mtrrs));\r
+\r
+ SystemParameter.MtrrSupported = FALSE;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ Result = MtrrGetAllMtrrs (&Mtrrs);\r
+ UT_ASSERT_EQUAL (Result, &Mtrrs);\r
+ UT_ASSERT_MEM_EQUAL (&ExpectedMtrrs, &Mtrrs, sizeof (ExpectedMtrrs));\r
+\r
+ //\r
+ // Expect ASSERT() if variable MTRR count is > MTRR_NUMBER_OF_VARIABLE_MTRR\r
+ //\r
+ SystemParameter.MtrrSupported = TRUE;\r
+ SystemParameter.VariableMtrrCount = MTRR_NUMBER_OF_VARIABLE_MTRR + 1;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ UT_EXPECT_ASSERT_FAILURE (MtrrGetAllMtrrs (&Mtrrs), NULL);\r
+\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Unit test of MtrrLib service MtrrSetAllMtrrs()\r
+\r
+ @param[in] Context Ignored\r
+\r
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test\r
+ case was successful.\r
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.\r
+\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+UnitTestMtrrSetAllMtrrs (\r
+ IN UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ MTRR_SETTINGS *Result;\r
+ MTRR_SETTINGS Mtrrs;\r
+ UINT32 Index;\r
+ MSR_IA32_MTRR_DEF_TYPE_REGISTER Default;\r
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;\r
+ MTRR_LIB_TEST_CONTEXT *LocalContext;\r
+\r
+ LocalContext = (MTRR_LIB_TEST_CONTEXT *) Context;\r
+\r
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));\r
+ InitializeMtrrRegs (&SystemParameter);\r
+\r
+ Default.Uint64 = 0;\r
+ Default.Bits.E = 1;\r
+ Default.Bits.FE = 1;\r
+ Default.Bits.Type = GenerateRandomCacheType ();\r
+\r
+ ZeroMem (&Mtrrs, sizeof (Mtrrs));\r
+ Mtrrs.MtrrDefType = Default.Uint64;\r
+ for (Index = 0; Index < SystemParameter.VariableMtrrCount; Index++) {\r
+ GenerateRandomMtrrPair (SystemParameter.PhysicalAddressBits, GenerateRandomCacheType (), &Mtrrs.Variables.Mtrr[Index], NULL);\r
+ }\r
+ Result = MtrrSetAllMtrrs (&Mtrrs);\r
+ UT_ASSERT_EQUAL (Result, &Mtrrs);\r
+\r
+ UT_ASSERT_EQUAL (AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE), Mtrrs.MtrrDefType);\r
+ for (Index = 0; Index < SystemParameter.VariableMtrrCount; Index++) {\r
+ UT_ASSERT_EQUAL (AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1)), Mtrrs.Variables.Mtrr[Index].Base);\r
+ UT_ASSERT_EQUAL (AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1)), Mtrrs.Variables.Mtrr[Index].Mask);\r
+ }\r
+\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Unit test of MtrrLib service MtrrGetMemoryAttributeInVariableMtrr()\r
+\r
+ @param[in] Context Ignored\r
+\r
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test\r
+ case was successful.\r
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.\r
+\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+UnitTestMtrrGetMemoryAttributeInVariableMtrr (\r
+ IN UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ MTRR_LIB_TEST_CONTEXT *LocalContext;\r
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;\r
+ UINT32 Result;\r
+ MTRR_VARIABLE_SETTING VariableSetting[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+ VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+ UINT64 ValidMtrrBitsMask;\r
+ UINT64 ValidMtrrAddressMask;\r
+ UINT32 Index;\r
+ MSR_IA32_MTRR_PHYSBASE_REGISTER Base;\r
+ MSR_IA32_MTRR_PHYSMASK_REGISTER Mask;\r
+\r
+ LocalContext = (MTRR_LIB_TEST_CONTEXT *) Context;\r
+\r
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));\r
+\r
+ InitializeMtrrRegs (&SystemParameter);\r
+\r
+ ValidMtrrBitsMask = (1ull << SystemParameter.PhysicalAddressBits) - 1;\r
+ ValidMtrrAddressMask = ValidMtrrBitsMask & 0xfffffffffffff000ULL;\r
+\r
+ for (Index = 0; Index < SystemParameter.VariableMtrrCount; Index++) {\r
+ GenerateRandomMtrrPair (SystemParameter.PhysicalAddressBits, GenerateRandomCacheType (), &VariableSetting[Index], NULL);\r
+ AsmWriteMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1), VariableSetting[Index].Base);\r
+ AsmWriteMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1), VariableSetting[Index].Mask);\r
+ }\r
+ Result = MtrrGetMemoryAttributeInVariableMtrr (ValidMtrrBitsMask, ValidMtrrAddressMask, VariableMtrr);\r
+ UT_ASSERT_EQUAL (Result, SystemParameter.VariableMtrrCount);\r
+\r
+ for (Index = 0; Index < SystemParameter.VariableMtrrCount; Index++) {\r
+ Base.Uint64 = VariableMtrr[Index].BaseAddress;\r
+ Base.Bits.Type = (UINT32) VariableMtrr[Index].Type;\r
+ UT_ASSERT_EQUAL (Base.Uint64, VariableSetting[Index].Base);\r
+\r
+ Mask.Uint64 = ~(VariableMtrr[Index].Length - 1) & ValidMtrrBitsMask;\r
+ Mask.Bits.V = 1;\r
+ UT_ASSERT_EQUAL (Mask.Uint64, VariableSetting[Index].Mask);\r
+ }\r
+\r
+ //\r
+ // Negative test case when MTRRs are not supported\r
+ //\r
+ SystemParameter.MtrrSupported = FALSE;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ Result = MtrrGetMemoryAttributeInVariableMtrr (ValidMtrrBitsMask, ValidMtrrAddressMask, VariableMtrr);\r
+ UT_ASSERT_EQUAL (Result, 0);\r
+\r
+ //\r
+ // Expect ASSERT() if variable MTRR count is > MTRR_NUMBER_OF_VARIABLE_MTRR\r
+ //\r
+ SystemParameter.MtrrSupported = TRUE;\r
+ SystemParameter.VariableMtrrCount = MTRR_NUMBER_OF_VARIABLE_MTRR + 1;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ UT_EXPECT_ASSERT_FAILURE (MtrrGetMemoryAttributeInVariableMtrr (ValidMtrrBitsMask, ValidMtrrAddressMask, VariableMtrr), NULL);\r
+\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Unit test of MtrrLib service MtrrDebugPrintAllMtrrs()\r
+\r
+ @param[in] Context Ignored\r
+\r
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test\r
+ case was successful.\r
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.\r
+\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+UnitTestMtrrDebugPrintAllMtrrs (\r
+ IN UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Unit test of MtrrLib service MtrrGetDefaultMemoryType().\r
+\r
+ @param[in] Context Ignored\r
+\r
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test\r
+ case was successful.\r
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.\r
+\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+UnitTestMtrrGetDefaultMemoryType (\r
+ IN UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ MTRR_LIB_TEST_CONTEXT *LocalContext;\r
+ UINTN Index;\r
+ MTRR_MEMORY_CACHE_TYPE Result;\r
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;\r
+ MTRR_MEMORY_CACHE_TYPE CacheType[5];\r
+\r
+ CacheType[0] = CacheUncacheable;\r
+ CacheType[1] = CacheWriteCombining;\r
+ CacheType[2] = CacheWriteThrough;\r
+ CacheType[3] = CacheWriteProtected;\r
+ CacheType[4] = CacheWriteBack;\r
+\r
+ LocalContext = (MTRR_LIB_TEST_CONTEXT *) Context;\r
+\r
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));\r
+ //\r
+ // If MTRRs are supported, then always return the cache type in the MSR\r
+ // MSR_IA32_MTRR_DEF_TYPE\r
+ //\r
+ for (Index = 0; Index < ARRAY_SIZE (CacheType); Index++) {\r
+ SystemParameter.DefaultCacheType = CacheType[Index];\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ Result = MtrrGetDefaultMemoryType ();\r
+ UT_ASSERT_EQUAL (Result, SystemParameter.DefaultCacheType);\r
+ }\r
+\r
+ //\r
+ // If MTRRs are not supported, then always return CacheUncacheable\r
+ //\r
+ SystemParameter.MtrrSupported = FALSE;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ Result = MtrrGetDefaultMemoryType ();\r
+ UT_ASSERT_EQUAL (Result, CacheUncacheable);\r
+\r
+ SystemParameter.MtrrSupported = TRUE;\r
+ SystemParameter.FixedMtrrSupported = FALSE;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ Result = MtrrGetDefaultMemoryType ();\r
+ UT_ASSERT_EQUAL (Result, CacheUncacheable);\r
+\r
+ SystemParameter.MtrrSupported = TRUE;\r
+ SystemParameter.FixedMtrrSupported = TRUE;\r
+ SystemParameter.VariableMtrrCount = 0;\r
+ InitializeMtrrRegs (&SystemParameter);\r
+ Result = MtrrGetDefaultMemoryType ();\r
+ UT_ASSERT_EQUAL (Result, CacheUncacheable);\r
+\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Unit test of MtrrLib service MtrrSetMemoryAttributeInMtrrSettings().\r
+\r
+ @param[in] Context Ignored\r
+\r
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test\r
+ case was successful.\r
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.\r
+\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+UnitTestMtrrSetMemoryAttributeInMtrrSettings (\r
+ IN UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter;\r
+ RETURN_STATUS Status;\r
+ UINT32 UcCount;\r
+ UINT32 WtCount;\r
+ UINT32 WbCount;\r
+ UINT32 WpCount;\r
+ UINT32 WcCount;\r
+\r
+ UINTN MtrrIndex;\r
+ UINTN Index;\r
+ MTRR_SETTINGS LocalMtrrs;\r
+\r
+ MTRR_MEMORY_RANGE RawMtrrRange[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+ MTRR_MEMORY_RANGE ExpectedMemoryRanges[MTRR_NUMBER_OF_FIXED_MTRR * sizeof (UINT64) + 2 * MTRR_NUMBER_OF_VARIABLE_MTRR + 1];\r
+ UINT32 ExpectedVariableMtrrUsage;\r
+ UINTN ExpectedMemoryRangesCount;\r
+\r
+ MTRR_MEMORY_RANGE ActualMemoryRanges[MTRR_NUMBER_OF_FIXED_MTRR * sizeof (UINT64) + 2 * MTRR_NUMBER_OF_VARIABLE_MTRR + 1];\r
+ UINT32 ActualVariableMtrrUsage;\r
+ UINTN ActualMemoryRangesCount;\r
+\r
+ MTRR_SETTINGS *Mtrrs[2];\r
+\r
+ SystemParameter = (MTRR_LIB_SYSTEM_PARAMETER *) Context;\r
+ GenerateRandomMemoryTypeCombination (\r
+ SystemParameter->VariableMtrrCount - PatchPcdGet32 (PcdCpuNumberOfReservedVariableMtrrs),\r
+ &UcCount, &WtCount, &WbCount, &WpCount, &WcCount\r
+ );\r
+ GenerateValidAndConfigurableMtrrPairs (\r
+ SystemParameter->PhysicalAddressBits, RawMtrrRange,\r
+ UcCount, WtCount, WbCount, WpCount, WcCount\r
+ );\r
+\r
+ ExpectedVariableMtrrUsage = UcCount + WtCount + WbCount + WpCount + WcCount;\r
+ ExpectedMemoryRangesCount = ARRAY_SIZE (ExpectedMemoryRanges);\r
+ GetEffectiveMemoryRanges (\r
+ SystemParameter->DefaultCacheType,\r
+ SystemParameter->PhysicalAddressBits,\r
+ RawMtrrRange, ExpectedVariableMtrrUsage,\r
+ ExpectedMemoryRanges, &ExpectedMemoryRangesCount\r
+ );\r
+\r
+ UT_LOG_INFO ("--- Expected Memory Ranges [%d] ---\n", ExpectedMemoryRangesCount);\r
+ DumpMemoryRanges (ExpectedMemoryRanges, ExpectedMemoryRangesCount);\r
+ //\r
+ // Default cache type is always an INPUT\r
+ //\r
+ ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs));\r
+ LocalMtrrs.MtrrDefType = MtrrGetDefaultMemoryType ();\r
+ Mtrrs[0] = &LocalMtrrs;\r
+ Mtrrs[1] = NULL;\r
+\r
+ for (MtrrIndex = 0; MtrrIndex < ARRAY_SIZE (Mtrrs); MtrrIndex++) {\r
+ for (Index = 0; Index < ExpectedMemoryRangesCount; Index++) {\r
+ Status = MtrrSetMemoryAttributeInMtrrSettings (\r
+ Mtrrs[MtrrIndex],\r
+ ExpectedMemoryRanges[Index].BaseAddress,\r
+ ExpectedMemoryRanges[Index].Length,\r
+ ExpectedMemoryRanges[Index].Type\r
+ );\r
+ UT_ASSERT_TRUE (Status == RETURN_SUCCESS || Status == RETURN_OUT_OF_RESOURCES || Status == RETURN_BUFFER_TOO_SMALL);\r
+ if (Status == RETURN_OUT_OF_RESOURCES || Status == RETURN_BUFFER_TOO_SMALL) {\r
+ return UNIT_TEST_SKIPPED;\r
+ }\r
+ }\r
+\r
+ if (Mtrrs[MtrrIndex] == NULL) {\r
+ ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs));\r
+ MtrrGetAllMtrrs (&LocalMtrrs);\r
+ }\r
+ ActualMemoryRangesCount = ARRAY_SIZE (ActualMemoryRanges);\r
+ CollectTestResult (\r
+ SystemParameter->DefaultCacheType, SystemParameter->PhysicalAddressBits, SystemParameter->VariableMtrrCount,\r
+ &LocalMtrrs, ActualMemoryRanges, &ActualMemoryRangesCount, &ActualVariableMtrrUsage\r
+ );\r
+ UT_LOG_INFO ("--- Actual Memory Ranges [%d] ---\n", ActualMemoryRangesCount);\r
+ DumpMemoryRanges (ActualMemoryRanges, ActualMemoryRangesCount);\r
+ VerifyMemoryRanges (ExpectedMemoryRanges, ExpectedMemoryRangesCount, ActualMemoryRanges, ActualMemoryRangesCount);\r
+ UT_ASSERT_TRUE (ExpectedVariableMtrrUsage >= ActualVariableMtrrUsage);\r
+\r
+ ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs));\r
+ }\r
+\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+\r
+/**\r
+ Prep routine for UnitTestGetFirmwareVariableMtrrCount().\r
+\r
+ @param Context Point to a UINT32 data to save the PcdCpuNumberOfReservedVariableMtrrs.\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+SavePcdValue (\r
+ UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *LocalContext;\r
+\r
+ LocalContext = (MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *) Context;\r
+ LocalContext->NumberOfReservedVariableMtrrs = PatchPcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Clean up routine for UnitTestGetFirmwareVariableMtrrCount().\r
+\r
+ @param Context Point to a UINT32 data to save the PcdCpuNumberOfReservedVariableMtrrs.\r
+**/\r
+VOID\r
+EFIAPI\r
+RestorePcdValue (\r
+ UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *LocalContext;\r
+\r
+ LocalContext = (MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *) Context;\r
+ PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, LocalContext->NumberOfReservedVariableMtrrs);\r
+}\r
+\r
+/**\r
+ Initialize the unit test framework, suite, and unit tests for the\r
+ ResetSystemLib and run the ResetSystemLib unit test.\r
+\r
+ @param Iteration Iteration of testing MtrrSetMemoryAttributeInMtrrSettings\r
+ and MtrrSetMemoryAttributesInMtrrSettings using random inputs.\r
+\r
+ @retval EFI_SUCCESS All test cases were dispatched.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to\r
+ initialize the unit tests.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestingEntry (\r
+ UINTN Iteration\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UNIT_TEST_FRAMEWORK_HANDLE Framework;\r
+ UNIT_TEST_SUITE_HANDLE MtrrApiTests;\r
+ UINTN Index;\r
+ UINTN SystemIndex;\r
+ MTRR_LIB_TEST_CONTEXT Context;\r
+ MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT GetFirmwareVariableMtrrCountContext;\r
+\r
+ Context.SystemParameter = &mDefaultSystemParameter;\r
+ GetFirmwareVariableMtrrCountContext.SystemParameter = &mDefaultSystemParameter;\r
+ Framework = NULL;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION));\r
+\r
+ //\r
+ // Setup the test framework for running the tests.\r
+ //\r
+ Status = InitUnitTestFramework (&Framework, UNIT_TEST_APP_NAME, gEfiCallerBaseName, UNIT_TEST_APP_VERSION);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));\r
+ goto EXIT;\r
+ }\r
+\r
+ //\r
+ // --------------Suite-----------Description--------------Name----------Function--------Pre---Post-------------------Context-----------\r
+ //\r
+\r
+ //\r
+ // Populate the MtrrLib API Unit Test Suite.\r
+ //\r
+ Status = CreateUnitTestSuite (&MtrrApiTests, Framework, "MtrrLib API Tests", "MtrrLib.MtrrLib", NULL, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for MtrrLib API Tests\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto EXIT;\r
+ }\r
+ AddTestCase (MtrrApiTests, "Test IsMtrrSupported", "MtrrSupported", UnitTestIsMtrrSupported, NULL, NULL, &Context);\r
+ AddTestCase (MtrrApiTests, "Test GetVariableMtrrCount", "GetVariableMtrrCount", UnitTestGetVariableMtrrCount, NULL, NULL, &Context);\r
+ AddTestCase (MtrrApiTests, "Test GetFirmwareVariableMtrrCount", "GetFirmwareVariableMtrrCount", UnitTestGetFirmwareVariableMtrrCount, SavePcdValue, RestorePcdValue, &GetFirmwareVariableMtrrCountContext);\r
+ AddTestCase (MtrrApiTests, "Test MtrrGetMemoryAttribute", "MtrrGetMemoryAttribute", UnitTestMtrrGetMemoryAttribute, NULL, NULL, &Context);\r
+ AddTestCase (MtrrApiTests, "Test MtrrGetFixedMtrr", "MtrrGetFixedMtrr", UnitTestMtrrGetFixedMtrr, NULL, NULL, &Context);\r
+ AddTestCase (MtrrApiTests, "Test MtrrGetAllMtrrs", "MtrrGetAllMtrrs", UnitTestMtrrGetAllMtrrs, NULL, NULL, &Context);\r
+ AddTestCase (MtrrApiTests, "Test MtrrSetAllMtrrs", "MtrrSetAllMtrrs", UnitTestMtrrSetAllMtrrs, NULL, NULL, &Context);\r
+ AddTestCase (MtrrApiTests, "Test MtrrGetMemoryAttributeInVariableMtrr", "MtrrGetMemoryAttributeInVariableMtrr", UnitTestMtrrGetMemoryAttributeInVariableMtrr, NULL, NULL, &Context);\r
+ AddTestCase (MtrrApiTests, "Test MtrrDebugPrintAllMtrrs", "MtrrDebugPrintAllMtrrs", UnitTestMtrrDebugPrintAllMtrrs, NULL, NULL, &Context);\r
+ AddTestCase (MtrrApiTests, "Test MtrrGetDefaultMemoryType", "MtrrGetDefaultMemoryType", UnitTestMtrrGetDefaultMemoryType, NULL, NULL, &Context);\r
+\r
+ for (SystemIndex = 0; SystemIndex < ARRAY_SIZE (mSystemParameters); SystemIndex++) {\r
+ for (Index = 0; Index < Iteration; Index++) {\r
+ AddTestCase (MtrrApiTests, "Test InvalidMemoryLayouts", "InvalidMemoryLayouts", UnitTestInvalidMemoryLayouts, InitializeSystem, NULL, &mSystemParameters[SystemIndex]);\r
+ AddTestCase (MtrrApiTests, "Test MtrrSetMemoryAttributeInMtrrSettings", "MtrrSetMemoryAttributeInMtrrSettings", UnitTestMtrrSetMemoryAttributeInMtrrSettings, InitializeSystem, NULL, &mSystemParameters[SystemIndex]);\r
+ AddTestCase (MtrrApiTests, "Test MtrrSetMemoryAttributesInMtrrSettings", "MtrrSetMemoryAttributesInMtrrSettings", UnitTestMtrrSetMemoryAttributesInMtrrSettings, InitializeSystem, NULL, &mSystemParameters[SystemIndex]);\r
+ }\r
+ }\r
+ //\r
+ // Execute the tests.\r
+ //\r
+ srand ((unsigned int) time (NULL));\r
+ Status = RunAllTestSuites (Framework);\r
+\r
+EXIT:\r
+ if (Framework != NULL) {\r
+ FreeUnitTestFramework (Framework);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Standard POSIX C entry point for host based unit test execution.\r
+\r
+ @param Argc Number of arguments.\r
+ @param Argv Array of arguments.\r
+\r
+ @return Test application exit code.\r
+**/\r
+INT32\r
+main (\r
+ INT32 Argc,\r
+ CHAR8 *Argv[]\r
+ )\r
+{\r
+ UINTN Iteration;\r
+\r
+ //\r
+ // First parameter specifies the test iterations.\r
+ // Default is 10.\r
+ //\r
+ Iteration = 10;\r
+ if (Argc == 2) {\r
+ Iteration = atoi (Argv[1]);\r
+ }\r
+ return UnitTestingEntry (Iteration);\r
+}\r
--- /dev/null
+/** @file\r
+ Unit tests of the MtrrLib instance of the MtrrLib class\r
+\r
+ Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "MtrrLibUnitTest.h"\r
+\r
+MTRR_MEMORY_CACHE_TYPE mMemoryCacheTypes[] = {\r
+ CacheUncacheable, CacheWriteCombining, CacheWriteThrough, CacheWriteProtected, CacheWriteBack\r
+ };\r
+\r
+UINT64 mFixedMtrrsValue[MTRR_NUMBER_OF_FIXED_MTRR];\r
+MSR_IA32_MTRR_PHYSBASE_REGISTER mVariableMtrrsPhysBase[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+MSR_IA32_MTRR_PHYSMASK_REGISTER mVariableMtrrsPhysMask[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+MSR_IA32_MTRR_DEF_TYPE_REGISTER mDefTypeMsr;\r
+MSR_IA32_MTRRCAP_REGISTER mMtrrCapMsr;\r
+CPUID_VERSION_INFO_EDX mCpuidVersionInfoEdx;\r
+CPUID_VIR_PHY_ADDRESS_SIZE_EAX mCpuidVirPhyAddressSizeEax;\r
+\r
+/**\r
+ Retrieves CPUID information.\r
+\r
+ Executes the CPUID instruction with EAX set to the value specified by Index.\r
+ This function always returns Index.\r
+ If Eax is not NULL, then the value of EAX after CPUID is returned in Eax.\r
+ If Ebx is not NULL, then the value of EBX after CPUID is returned in Ebx.\r
+ If Ecx is not NULL, then the value of ECX after CPUID is returned in Ecx.\r
+ If Edx is not NULL, then the value of EDX after CPUID is returned in Edx.\r
+ This function is only available on IA-32 and x64.\r
+\r
+ @param Index The 32-bit value to load into EAX prior to invoking the CPUID\r
+ instruction.\r
+ @param Eax The pointer to the 32-bit EAX value returned by the CPUID\r
+ instruction. This is an optional parameter that may be NULL.\r
+ @param Ebx The pointer to the 32-bit EBX value returned by the CPUID\r
+ instruction. This is an optional parameter that may be NULL.\r
+ @param Ecx The pointer to the 32-bit ECX value returned by the CPUID\r
+ instruction. This is an optional parameter that may be NULL.\r
+ @param Edx The pointer to the 32-bit EDX value returned by the CPUID\r
+ instruction. This is an optional parameter that may be NULL.\r
+\r
+ @return Index.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+UnitTestMtrrLibAsmCpuid (\r
+ IN UINT32 Index,\r
+ OUT UINT32 *Eax, OPTIONAL\r
+ OUT UINT32 *Ebx, OPTIONAL\r
+ OUT UINT32 *Ecx, OPTIONAL\r
+ OUT UINT32 *Edx OPTIONAL\r
+ )\r
+{\r
+ switch (Index) {\r
+ case CPUID_VERSION_INFO:\r
+ if (Edx != NULL) {\r
+ *Edx = mCpuidVersionInfoEdx.Uint32;\r
+ }\r
+ return Index;\r
+ break;\r
+ case CPUID_EXTENDED_FUNCTION:\r
+ if (Eax != NULL) {\r
+ *Eax = CPUID_VIR_PHY_ADDRESS_SIZE;\r
+ }\r
+ return Index;\r
+ break;\r
+ case CPUID_VIR_PHY_ADDRESS_SIZE:\r
+ if (Eax != NULL) {\r
+ *Eax = mCpuidVirPhyAddressSizeEax.Uint32;\r
+ }\r
+ return Index;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Should never fall through to here\r
+ //\r
+ ASSERT(FALSE);\r
+ return Index;\r
+}\r
+\r
+/**\r
+ Returns a 64-bit Machine Specific Register(MSR).\r
+\r
+ Reads and returns the 64-bit MSR specified by Index. No parameter checking is\r
+ performed on Index, and some Index values may cause CPU exceptions. The\r
+ caller must either guarantee that Index is valid, or the caller must set up\r
+ exception handlers to catch the exceptions. This function is only available\r
+ on IA-32 and x64.\r
+\r
+ @param MsrIndex The 32-bit MSR index to read.\r
+\r
+ @return The value of the MSR identified by MsrIndex.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+UnitTestMtrrLibAsmReadMsr64(\r
+ IN UINT32 MsrIndex\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < ARRAY_SIZE (mFixedMtrrsValue); Index++) {\r
+ if (MsrIndex == mFixedMtrrsIndex[Index]) {\r
+ return mFixedMtrrsValue[Index];\r
+ }\r
+ }\r
+\r
+ if ((MsrIndex >= MSR_IA32_MTRR_PHYSBASE0) &&\r
+ (MsrIndex <= MSR_IA32_MTRR_PHYSMASK0 + (MTRR_NUMBER_OF_VARIABLE_MTRR << 1))) {\r
+ if (MsrIndex % 2 == 0) {\r
+ Index = (MsrIndex - MSR_IA32_MTRR_PHYSBASE0) >> 1;\r
+ return mVariableMtrrsPhysBase[Index].Uint64;\r
+ } else {\r
+ Index = (MsrIndex - MSR_IA32_MTRR_PHYSMASK0) >> 1;\r
+ return mVariableMtrrsPhysMask[Index].Uint64;\r
+ }\r
+ }\r
+\r
+ if (MsrIndex == MSR_IA32_MTRR_DEF_TYPE) {\r
+ return mDefTypeMsr.Uint64;\r
+ }\r
+\r
+ if (MsrIndex == MSR_IA32_MTRRCAP) {\r
+ return mMtrrCapMsr.Uint64;\r
+ }\r
+\r
+ //\r
+ // Should never fall through to here\r
+ //\r
+ ASSERT(FALSE);\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Writes a 64-bit value to a Machine Specific Register(MSR), and returns the\r
+ value.\r
+\r
+ Writes the 64-bit value specified by Value to the MSR specified by Index. The\r
+ 64-bit value written to the MSR is returned. No parameter checking is\r
+ performed on Index or Value, and some of these may cause CPU exceptions. The\r
+ caller must either guarantee that Index and Value are valid, or the caller\r
+ must establish proper exception handlers. This function is only available on\r
+ IA-32 and x64.\r
+\r
+ @param MsrIndex The 32-bit MSR index to write.\r
+ @param Value The 64-bit value to write to the MSR.\r
+\r
+ @return Value\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+UnitTestMtrrLibAsmWriteMsr64(\r
+ IN UINT32 MsrIndex,\r
+ IN UINT64 Value\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < ARRAY_SIZE (mFixedMtrrsValue); Index++) {\r
+ if (MsrIndex == mFixedMtrrsIndex[Index]) {\r
+ mFixedMtrrsValue[Index] = Value;\r
+ return Value;\r
+ }\r
+ }\r
+\r
+ if ((MsrIndex >= MSR_IA32_MTRR_PHYSBASE0) &&\r
+ (MsrIndex <= MSR_IA32_MTRR_PHYSMASK0 + (MTRR_NUMBER_OF_VARIABLE_MTRR << 1))) {\r
+ if (MsrIndex % 2 == 0) {\r
+ Index = (MsrIndex - MSR_IA32_MTRR_PHYSBASE0) >> 1;\r
+ mVariableMtrrsPhysBase[Index].Uint64 = Value;\r
+ return Value;\r
+ } else {\r
+ Index = (MsrIndex - MSR_IA32_MTRR_PHYSMASK0) >> 1;\r
+ mVariableMtrrsPhysMask[Index].Uint64 = Value;\r
+ return Value;\r
+ }\r
+ }\r
+\r
+ if (MsrIndex == MSR_IA32_MTRR_DEF_TYPE) {\r
+ mDefTypeMsr.Uint64 = Value;\r
+ return Value;\r
+ }\r
+\r
+ if (MsrIndex == MSR_IA32_MTRRCAP) {\r
+ mMtrrCapMsr.Uint64 = Value;\r
+ return Value;\r
+ }\r
+\r
+ //\r
+ // Should never fall through to here\r
+ //\r
+ ASSERT(FALSE);\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Initialize the MTRR registers.\r
+\r
+ @param SystemParameter System parameter that controls the MTRR registers initialization.\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+InitializeMtrrRegs (\r
+ IN MTRR_LIB_SYSTEM_PARAMETER *SystemParameter\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ SetMem (mFixedMtrrsValue, sizeof (mFixedMtrrsValue), SystemParameter->DefaultCacheType);\r
+\r
+ for (Index = 0; Index < ARRAY_SIZE (mVariableMtrrsPhysBase); Index++) {\r
+ mVariableMtrrsPhysBase[Index].Uint64 = 0;\r
+ mVariableMtrrsPhysBase[Index].Bits.Type = SystemParameter->DefaultCacheType;\r
+ mVariableMtrrsPhysBase[Index].Bits.Reserved1 = 0;\r
+\r
+ mVariableMtrrsPhysMask[Index].Uint64 = 0;\r
+ mVariableMtrrsPhysMask[Index].Bits.V = 0;\r
+ mVariableMtrrsPhysMask[Index].Bits.Reserved1 = 0;\r
+ }\r
+\r
+ mDefTypeMsr.Bits.E = 1;\r
+ mDefTypeMsr.Bits.FE = 1;\r
+ mDefTypeMsr.Bits.Type = SystemParameter->DefaultCacheType;\r
+ mDefTypeMsr.Bits.Reserved1 = 0;\r
+ mDefTypeMsr.Bits.Reserved2 = 0;\r
+ mDefTypeMsr.Bits.Reserved3 = 0;\r
+\r
+ mMtrrCapMsr.Bits.SMRR = 0;\r
+ mMtrrCapMsr.Bits.WC = 0;\r
+ mMtrrCapMsr.Bits.VCNT = SystemParameter->VariableMtrrCount;\r
+ mMtrrCapMsr.Bits.FIX = SystemParameter->FixedMtrrSupported;\r
+ mMtrrCapMsr.Bits.Reserved1 = 0;\r
+ mMtrrCapMsr.Bits.Reserved2 = 0;\r
+ mMtrrCapMsr.Bits.Reserved3 = 0;\r
+\r
+ mCpuidVersionInfoEdx.Bits.MTRR = SystemParameter->MtrrSupported;\r
+ mCpuidVirPhyAddressSizeEax.Bits.PhysicalAddressBits = SystemParameter->PhysicalAddressBits;\r
+\r
+ //\r
+ // Hook BaseLib functions used by MtrrLib that require some emulation.\r
+ //\r
+ gUnitTestHostBaseLib.X86->AsmCpuid = UnitTestMtrrLibAsmCpuid;\r
+ gUnitTestHostBaseLib.X86->AsmReadMsr64 = UnitTestMtrrLibAsmReadMsr64;\r
+ gUnitTestHostBaseLib.X86->AsmWriteMsr64 = UnitTestMtrrLibAsmWriteMsr64;\r
+\r
+ return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+ Initialize the MTRR registers.\r
+\r
+ @param Context System parameter that controls the MTRR registers initialization.\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+InitializeSystem (\r
+ IN UNIT_TEST_CONTEXT Context\r
+ )\r
+{\r
+ return InitializeMtrrRegs ((MTRR_LIB_SYSTEM_PARAMETER *) Context);\r
+}\r
+\r
+/**\r
+ Collect the test result.\r
+\r
+ @param DefaultType Default memory type.\r
+ @param PhysicalAddressBits Physical address bits.\r
+ @param VariableMtrrCount Count of variable MTRRs.\r
+ @param Mtrrs MTRR settings to collect from.\r
+ @param Ranges Return the memory ranges.\r
+ @param RangeCount Return the count of memory ranges.\r
+ @param MtrrCount Return the count of variable MTRRs being used.\r
+**/\r
+VOID\r
+CollectTestResult (\r
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
+ IN UINT32 PhysicalAddressBits,\r
+ IN UINT32 VariableMtrrCount,\r
+ IN MTRR_SETTINGS *Mtrrs,\r
+ OUT MTRR_MEMORY_RANGE *Ranges,\r
+ IN OUT UINTN *RangeCount,\r
+ OUT UINT32 *MtrrCount\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINT64 MtrrValidBitsMask;\r
+ UINT64 MtrrValidAddressMask;\r
+ MTRR_MEMORY_RANGE RawMemoryRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)];\r
+\r
+ ASSERT (Mtrrs != NULL);\r
+ ASSERT (VariableMtrrCount <= ARRAY_SIZE (Mtrrs->Variables.Mtrr));\r
+\r
+ MtrrValidBitsMask = (1ull << PhysicalAddressBits) - 1;\r
+ MtrrValidAddressMask = MtrrValidBitsMask & ~0xFFFull;\r
+\r
+ *MtrrCount = 0;\r
+ for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+ if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &Mtrrs->Variables.Mtrr[Index].Mask)->Bits.V == 1) {\r
+ RawMemoryRanges[*MtrrCount].BaseAddress = Mtrrs->Variables.Mtrr[Index].Base & MtrrValidAddressMask;\r
+ RawMemoryRanges[*MtrrCount].Type =\r
+ ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &Mtrrs->Variables.Mtrr[Index].Base)->Bits.Type;\r
+ RawMemoryRanges[*MtrrCount].Length =\r
+ ((~(Mtrrs->Variables.Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
+ (*MtrrCount)++;\r
+ }\r
+ }\r
+\r
+ GetEffectiveMemoryRanges (DefaultType, PhysicalAddressBits, RawMemoryRanges, *MtrrCount, Ranges, RangeCount);\r
+}\r
+\r
+/**\r
+ Return a 32bit random number.\r
+\r
+ @param Start Start of the random number range.\r
+ @param Limit Limit of the random number range.\r
+ @return 32bit random number\r
+**/\r
+UINT32\r
+Random32 (\r
+ UINT32 Start,\r
+ UINT32 Limit\r
+ )\r
+{\r
+ return (UINT32) (((double) rand () / RAND_MAX) * (Limit - Start)) + Start;\r
+}\r
+\r
+/**\r
+ Return a 64bit random number.\r
+\r
+ @param Start Start of the random number range.\r
+ @param Limit Limit of the random number range.\r
+ @return 64bit random number\r
+**/\r
+UINT64\r
+Random64 (\r
+ UINT64 Start,\r
+ UINT64 Limit\r
+ )\r
+{\r
+ return (UINT64) (((double) rand () / RAND_MAX) * (Limit - Start)) + Start;\r
+}\r
+\r
+/**\r
+ Generate random MTRR BASE/MASK for a specified type.\r
+\r
+ @param PhysicalAddressBits Physical address bits.\r
+ @param CacheType Cache type.\r
+ @param MtrrPair Return the random MTRR.\r
+ @param MtrrMemoryRange Return the random memory range.\r
+**/\r
+VOID\r
+GenerateRandomMtrrPair (\r
+ IN UINT32 PhysicalAddressBits,\r
+ IN MTRR_MEMORY_CACHE_TYPE CacheType,\r
+ OUT MTRR_VARIABLE_SETTING *MtrrPair, OPTIONAL\r
+ OUT MTRR_MEMORY_RANGE *MtrrMemoryRange OPTIONAL\r
+ )\r
+{\r
+ MSR_IA32_MTRR_PHYSBASE_REGISTER PhysBase;\r
+ MSR_IA32_MTRR_PHYSMASK_REGISTER PhysMask;\r
+ UINT32 SizeShift;\r
+ UINT32 BaseShift;\r
+ UINT64 RandomBoundary;\r
+ UINT64 MaxPhysicalAddress;\r
+ UINT64 RangeSize;\r
+ UINT64 RangeBase;\r
+ UINT64 PhysBasePhyMaskValidBitsMask;\r
+\r
+ MaxPhysicalAddress = 1ull << PhysicalAddressBits;\r
+ do {\r
+ SizeShift = Random32 (12, PhysicalAddressBits - 1);\r
+ RangeSize = 1ull << SizeShift;\r
+\r
+ BaseShift = Random32 (SizeShift, PhysicalAddressBits - 1);\r
+ RandomBoundary = Random64 (0, 1ull << (PhysicalAddressBits - BaseShift));\r
+ RangeBase = RandomBoundary << BaseShift;\r
+ } while (RangeBase < SIZE_1MB || RangeBase > MaxPhysicalAddress - 1);\r
+\r
+ PhysBasePhyMaskValidBitsMask = (MaxPhysicalAddress - 1) & 0xfffffffffffff000ULL;\r
+\r
+ PhysBase.Uint64 = 0;\r
+ PhysBase.Bits.Type = CacheType;\r
+ PhysBase.Uint64 |= RangeBase & PhysBasePhyMaskValidBitsMask;\r
+ PhysMask.Uint64 = 0;\r
+ PhysMask.Bits.V = 1;\r
+ PhysMask.Uint64 |= ((~RangeSize) + 1) & PhysBasePhyMaskValidBitsMask;\r
+\r
+ if (MtrrPair != NULL) {\r
+ MtrrPair->Base = PhysBase.Uint64;\r
+ MtrrPair->Mask = PhysMask.Uint64;\r
+ }\r
+\r
+ if (MtrrMemoryRange != NULL) {\r
+ MtrrMemoryRange->BaseAddress = RangeBase;\r
+ MtrrMemoryRange->Length = RangeSize;\r
+ MtrrMemoryRange->Type = CacheType;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Check whether the Range overlaps with any one in Ranges.\r
+\r
+ @param Range The memory range to check.\r
+ @param Ranges The memory ranges.\r
+ @param Count Count of memory ranges.\r
+\r
+ @return TRUE when overlap exists.\r
+**/\r
+BOOLEAN\r
+RangesOverlap (\r
+ IN MTRR_MEMORY_RANGE *Range,\r
+ IN MTRR_MEMORY_RANGE *Ranges,\r
+ IN UINTN Count\r
+ )\r
+{\r
+ while (Count-- != 0) {\r
+ //\r
+ // Two ranges overlap when:\r
+ // 1. range#2.base is in the middle of range#1\r
+ // 2. range#1.base is in the middle of range#2\r
+ //\r
+ if ((Range->BaseAddress <= Ranges[Count].BaseAddress && Ranges[Count].BaseAddress < Range->BaseAddress + Range->Length)\r
+ || (Ranges[Count].BaseAddress <= Range->BaseAddress && Range->BaseAddress < Ranges[Count].BaseAddress + Ranges[Count].Length)) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Generate random MTRRs.\r
+\r
+ @param PhysicalAddressBits Physical address bits.\r
+ @param RawMemoryRanges Return the randomly generated MTRRs.\r
+ @param UcCount Count of Uncacheable MTRRs.\r
+ @param WtCount Count of Write Through MTRRs.\r
+ @param WbCount Count of Write Back MTRRs.\r
+ @param WpCount Count of Write Protected MTRRs.\r
+ @param WcCount Count of Write Combine MTRRs.\r
+**/\r
+VOID\r
+GenerateValidAndConfigurableMtrrPairs (\r
+ IN UINT32 PhysicalAddressBits,\r
+ IN OUT MTRR_MEMORY_RANGE *RawMemoryRanges,\r
+ IN UINT32 UcCount,\r
+ IN UINT32 WtCount,\r
+ IN UINT32 WbCount,\r
+ IN UINT32 WpCount,\r
+ IN UINT32 WcCount\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ //\r
+ // 1. Generate UC, WT, WB in order.\r
+ //\r
+ for (Index = 0; Index < UcCount; Index++) {\r
+ GenerateRandomMtrrPair (PhysicalAddressBits, CacheUncacheable, NULL, &RawMemoryRanges[Index]);\r
+ }\r
+\r
+ for (Index = UcCount; Index < UcCount + WtCount; Index++) {\r
+ GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteThrough, NULL, &RawMemoryRanges[Index]);\r
+ }\r
+\r
+ for (Index = UcCount + WtCount; Index < UcCount + WtCount + WbCount; Index++) {\r
+ GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteBack, NULL, &RawMemoryRanges[Index]);\r
+ }\r
+\r
+ //\r
+ // 2. Generate WP MTRR and DO NOT overlap with WT, WB.\r
+ //\r
+ for (Index = UcCount + WtCount + WbCount; Index < UcCount + WtCount + WbCount + WpCount; Index++) {\r
+ GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteProtected, NULL, &RawMemoryRanges[Index]);\r
+ while (RangesOverlap (&RawMemoryRanges[Index], &RawMemoryRanges[UcCount], WtCount + WbCount)) {\r
+ GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteProtected, NULL, &RawMemoryRanges[Index]);\r
+ }\r
+ }\r
+\r
+ //\r
+ // 3. Generate WC MTRR and DO NOT overlap with WT, WB, WP.\r
+ //\r
+ for (Index = UcCount + WtCount + WbCount + WpCount; Index < UcCount + WtCount + WbCount + WpCount + WcCount; Index++) {\r
+ GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteCombining, NULL, &RawMemoryRanges[Index]);\r
+ while (RangesOverlap (&RawMemoryRanges[Index], &RawMemoryRanges[UcCount], WtCount + WbCount + WpCount)) {\r
+ GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteCombining, NULL, &RawMemoryRanges[Index]);\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Return a random memory cache type.\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+GenerateRandomCacheType (\r
+ VOID\r
+ )\r
+{\r
+ return mMemoryCacheTypes[Random32 (0, ARRAY_SIZE (mMemoryCacheTypes) - 1)];\r
+}\r
+\r
+/**\r
+ Compare function used by qsort().\r
+**/\r
+\r
+/**\r
+ Compare function used by qsort().\r
+\r
+ @param Left Left operand to compare.\r
+ @param Right Right operand to compare.\r
+\r
+ @retval 0 Left == Right\r
+ @retval -1 Left < Right\r
+ @retval 1 Left > Right\r
+**/\r
+INT32\r
+CompareFuncUint64 (\r
+ CONST VOID * Left,\r
+ CONST VOID * Right\r
+ )\r
+{\r
+ INT64 Delta;\r
+ Delta = (*(UINT64*)Left - *(UINT64*)Right);\r
+ if (Delta > 0) {\r
+ return 1;\r
+ } else if (Delta == 0) {\r
+ return 0;\r
+ } else {\r
+ return -1;\r
+ }\r
+}\r
+\r
+/**\r
+ Determin the memory cache type for the Range.\r
+\r
+ @param DefaultType Default cache type.\r
+ @param Range The memory range to determin the cache type.\r
+ @param Ranges The entire memory ranges.\r
+ @param RangeCount Count of the entire memory ranges.\r
+**/\r
+VOID\r
+DetermineMemoryCacheType (\r
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
+ IN OUT MTRR_MEMORY_RANGE *Range,\r
+ IN MTRR_MEMORY_RANGE *Ranges,\r
+ IN UINT32 RangeCount\r
+ )\r
+{\r
+ UINT32 Index;\r
+ Range->Type = CacheInvalid;\r
+ for (Index = 0; Index < RangeCount; Index++) {\r
+ if (RangesOverlap (Range, &Ranges[Index], 1)) {\r
+ if (Ranges[Index].Type < Range->Type) {\r
+ Range->Type = Ranges[Index].Type;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (Range->Type == CacheInvalid) {\r
+ Range->Type = DefaultType;\r
+ }\r
+}\r
+\r
+/**\r
+ Get the index of the element that does NOT equals to Array[Index].\r
+\r
+ @param Index Current element.\r
+ @param Array Array to scan.\r
+ @param Count Count of the array.\r
+\r
+ @return Next element that doesn't equal to current one.\r
+**/\r
+UINT32\r
+GetNextDifferentElementInSortedArray (\r
+ IN UINT32 Index,\r
+ IN UINT64 *Array,\r
+ IN UINT32 Count\r
+ )\r
+{\r
+ UINT64 CurrentElement;\r
+ CurrentElement = Array[Index];\r
+ while (CurrentElement == Array[Index] && Index < Count) {\r
+ Index++;\r
+ }\r
+ return Index;\r
+}\r
+\r
+/**\r
+ Remove the duplicates from the array.\r
+\r
+ @param Array The array to operate on.\r
+ @param Count Count of the array.\r
+**/\r
+VOID\r
+RemoveDuplicatesInSortedArray (\r
+ IN OUT UINT64 *Array,\r
+ IN OUT UINT32 *Count\r
+ )\r
+{\r
+ UINT32 Index;\r
+ UINT32 NewCount;\r
+\r
+ Index = 0;\r
+ NewCount = 0;\r
+ while (Index < *Count) {\r
+ Array[NewCount] = Array[Index];\r
+ NewCount++;\r
+ Index = GetNextDifferentElementInSortedArray (Index, Array, *Count);\r
+ }\r
+ *Count = NewCount;\r
+}\r
+\r
+/**\r
+ Return TRUE when Address is in the Range.\r
+\r
+ @param Address The address to check.\r
+ @param Range The range to check.\r
+ @return TRUE when Address is in the Range.\r
+**/\r
+BOOLEAN\r
+AddressInRange (\r
+ IN UINT64 Address,\r
+ IN MTRR_MEMORY_RANGE Range\r
+ )\r
+{\r
+ return (Address >= Range.BaseAddress) && (Address <= Range.BaseAddress + Range.Length - 1);\r
+}\r
+\r
+/**\r
+ Get the overlap bit flag.\r
+\r
+ @param RawMemoryRanges Raw memory ranges.\r
+ @param RawMemoryRangeCount Count of raw memory ranges.\r
+ @param Address The address to check.\r
+**/\r
+UINT64\r
+GetOverlapBitFlag (\r
+ IN MTRR_MEMORY_RANGE *RawMemoryRanges,\r
+ IN UINT32 RawMemoryRangeCount,\r
+ IN UINT64 Address\r
+ )\r
+{\r
+ UINT64 OverlapBitFlag;\r
+ UINT32 Index;\r
+ OverlapBitFlag = 0;\r
+ for (Index = 0; Index < RawMemoryRangeCount; Index++) {\r
+ if (AddressInRange (Address, RawMemoryRanges[Index])) {\r
+ OverlapBitFlag |= (1ull << Index);\r
+ }\r
+ }\r
+\r
+ return OverlapBitFlag;\r
+}\r
+\r
+/**\r
+ Return the relationship between flags.\r
+\r
+ @param Flag1 Flag 1\r
+ @param Flag2 Flag 2\r
+\r
+ @retval 0 Flag1 == Flag2\r
+ @retval 1 Flag1 is a subset of Flag2\r
+ @retval 2 Flag2 is a subset of Flag1\r
+ @retval 3 No subset relations between Flag1 and Flag2.\r
+**/\r
+UINT32\r
+CheckOverlapBitFlagsRelation (\r
+ IN UINT64 Flag1,\r
+ IN UINT64 Flag2\r
+ )\r
+{\r
+ if (Flag1 == Flag2) return 0;\r
+ if ((Flag1 | Flag2) == Flag2) return 1;\r
+ if ((Flag1 | Flag2) == Flag1) return 2;\r
+ return 3;\r
+}\r
+\r
+/**\r
+ Return TRUE when the Endpoint is in any of the Ranges.\r
+\r
+ @param Endpoint The endpoint to check.\r
+ @param Ranges The memory ranges.\r
+ @param RangeCount Count of memory ranges.\r
+\r
+ @retval TRUE Endpoint is in one of the range.\r
+ @retval FALSE Endpoint is not in any of the ranges.\r
+**/\r
+BOOLEAN\r
+IsEndpointInRanges (\r
+ IN UINT64 Endpoint,\r
+ IN MTRR_MEMORY_RANGE *Ranges,\r
+ IN UINTN RangeCount\r
+ )\r
+{\r
+ UINT32 Index;\r
+ for (Index = 0; Index < RangeCount; Index++) {\r
+ if (AddressInRange (Endpoint, Ranges[Index])) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+\r
+/**\r
+ Compact adjacent ranges of the same type.\r
+\r
+ @param DefaultType Default memory type.\r
+ @param PhysicalAddressBits Physical address bits.\r
+ @param EffectiveMtrrMemoryRanges Memory ranges to compact.\r
+ @param EffectiveMtrrMemoryRangesCount Return the new count of memory ranges.\r
+**/\r
+VOID\r
+CompactAndExtendEffectiveMtrrMemoryRanges (\r
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
+ IN UINT32 PhysicalAddressBits,\r
+ IN OUT MTRR_MEMORY_RANGE **EffectiveMtrrMemoryRanges,\r
+ IN OUT UINTN *EffectiveMtrrMemoryRangesCount\r
+ )\r
+{\r
+ UINT64 MaxAddress;\r
+ UINTN NewRangesCountAtMost;\r
+ MTRR_MEMORY_RANGE *NewRanges;\r
+ UINTN NewRangesCountActual;\r
+ MTRR_MEMORY_RANGE *CurrentRangeInNewRanges;\r
+ MTRR_MEMORY_CACHE_TYPE CurrentRangeTypeInOldRanges;\r
+\r
+ MTRR_MEMORY_RANGE *OldRanges;\r
+ MTRR_MEMORY_RANGE OldLastRange;\r
+ UINTN OldRangesIndex;\r
+\r
+ NewRangesCountActual = 0;\r
+ NewRangesCountAtMost = *EffectiveMtrrMemoryRangesCount + 2; // At most with 2 more range entries.\r
+ NewRanges = (MTRR_MEMORY_RANGE *) calloc (NewRangesCountAtMost, sizeof (MTRR_MEMORY_RANGE));\r
+ OldRanges = *EffectiveMtrrMemoryRanges;\r
+ if (OldRanges[0].BaseAddress > 0) {\r
+ NewRanges[NewRangesCountActual].BaseAddress = 0;\r
+ NewRanges[NewRangesCountActual].Length = OldRanges[0].BaseAddress;\r
+ NewRanges[NewRangesCountActual].Type = DefaultType;\r
+ NewRangesCountActual++;\r
+ }\r
+\r
+ OldRangesIndex = 0;\r
+ while (OldRangesIndex < *EffectiveMtrrMemoryRangesCount) {\r
+ CurrentRangeTypeInOldRanges = OldRanges[OldRangesIndex].Type;\r
+ CurrentRangeInNewRanges = NULL;\r
+ if (NewRangesCountActual > 0) // We need to check CurrentNewRange first before generate a new NewRange.\r
+ {\r
+ CurrentRangeInNewRanges = &NewRanges[NewRangesCountActual - 1];\r
+ }\r
+ if (CurrentRangeInNewRanges != NULL && CurrentRangeInNewRanges->Type == CurrentRangeTypeInOldRanges) {\r
+ CurrentRangeInNewRanges->Length += OldRanges[OldRangesIndex].Length;\r
+ } else {\r
+ NewRanges[NewRangesCountActual].BaseAddress = OldRanges[OldRangesIndex].BaseAddress;\r
+ NewRanges[NewRangesCountActual].Length += OldRanges[OldRangesIndex].Length;\r
+ NewRanges[NewRangesCountActual].Type = CurrentRangeTypeInOldRanges;\r
+ while (OldRangesIndex + 1 < *EffectiveMtrrMemoryRangesCount && OldRanges[OldRangesIndex + 1].Type == CurrentRangeTypeInOldRanges)\r
+ {\r
+ OldRangesIndex++;\r
+ NewRanges[NewRangesCountActual].Length += OldRanges[OldRangesIndex].Length;\r
+ }\r
+ NewRangesCountActual++;\r
+ }\r
+\r
+ OldRangesIndex++;\r
+ }\r
+\r
+ MaxAddress = (1ull << PhysicalAddressBits) - 1;\r
+ OldLastRange = OldRanges[(*EffectiveMtrrMemoryRangesCount) - 1];\r
+ CurrentRangeInNewRanges = &NewRanges[NewRangesCountActual - 1];\r
+ if (OldLastRange.BaseAddress + OldLastRange.Length - 1 < MaxAddress) {\r
+ if (CurrentRangeInNewRanges->Type == DefaultType) {\r
+ CurrentRangeInNewRanges->Length = MaxAddress - CurrentRangeInNewRanges->BaseAddress + 1;\r
+ } else {\r
+ NewRanges[NewRangesCountActual].BaseAddress = OldLastRange.BaseAddress + OldLastRange.Length;\r
+ NewRanges[NewRangesCountActual].Length = MaxAddress - NewRanges[NewRangesCountActual].BaseAddress + 1;\r
+ NewRanges[NewRangesCountActual].Type = DefaultType;\r
+ NewRangesCountActual++;\r
+ }\r
+ }\r
+\r
+ free (*EffectiveMtrrMemoryRanges);\r
+ *EffectiveMtrrMemoryRanges = NewRanges;\r
+ *EffectiveMtrrMemoryRangesCount = NewRangesCountActual;\r
+}\r
+\r
+/**\r
+ Collect all the endpoints in the raw memory ranges.\r
+\r
+ @param Endpoints Return the collected endpoints.\r
+ @param EndPointCount Return the count of endpoints.\r
+ @param RawMemoryRanges Raw memory ranges.\r
+ @param RawMemoryRangeCount Count of raw memory ranges.\r
+**/\r
+VOID\r
+CollectEndpoints (\r
+ IN OUT UINT64 *Endpoints,\r
+ IN OUT UINT32 *EndPointCount,\r
+ IN MTRR_MEMORY_RANGE *RawMemoryRanges,\r
+ IN UINT32 RawMemoryRangeCount\r
+ )\r
+{\r
+ UINT32 Index;\r
+ UINT32 RawRangeIndex;\r
+\r
+ ASSERT ((RawMemoryRangeCount << 1) == *EndPointCount);\r
+\r
+ for (Index = 0; Index < *EndPointCount; Index += 2) {\r
+ RawRangeIndex = Index >> 1;\r
+ Endpoints[Index] = RawMemoryRanges[RawRangeIndex].BaseAddress;\r
+ Endpoints[Index + 1] = RawMemoryRanges[RawRangeIndex].BaseAddress + RawMemoryRanges[RawRangeIndex].Length - 1;\r
+ }\r
+\r
+ qsort (Endpoints, *EndPointCount, sizeof (UINT64), CompareFuncUint64);\r
+ RemoveDuplicatesInSortedArray (Endpoints, EndPointCount);\r
+}\r
+\r
+/**\r
+ Convert the MTRR BASE/MASK array to memory ranges.\r
+\r
+ @param DefaultType Default memory type.\r
+ @param PhysicalAddressBits Physical address bits.\r
+ @param RawMemoryRanges Raw memory ranges.\r
+ @param RawMemoryRangeCount Count of raw memory ranges.\r
+ @param MemoryRanges Memory ranges.\r
+ @param MemoryRangeCount Count of memory ranges.\r
+**/\r
+VOID\r
+GetEffectiveMemoryRanges (\r
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,\r
+ IN UINT32 PhysicalAddressBits,\r
+ IN MTRR_MEMORY_RANGE *RawMemoryRanges,\r
+ IN UINT32 RawMemoryRangeCount,\r
+ OUT MTRR_MEMORY_RANGE *MemoryRanges,\r
+ OUT UINTN *MemoryRangeCount\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINT32 AllEndPointsCount;\r
+ UINT64 *AllEndPointsInclusive;\r
+ UINT32 AllRangePiecesCountMax;\r
+ MTRR_MEMORY_RANGE *AllRangePieces;\r
+ UINTN AllRangePiecesCountActual;\r
+ UINT64 OverlapBitFlag1;\r
+ UINT64 OverlapBitFlag2;\r
+ INT32 OverlapFlagRelation;\r
+\r
+ if (RawMemoryRangeCount == 0) {\r
+ MemoryRanges[0].BaseAddress = 0;\r
+ MemoryRanges[0].Length = (1ull << PhysicalAddressBits);\r
+ MemoryRanges[0].Type = DefaultType;\r
+ *MemoryRangeCount = 1;\r
+ return;\r
+ }\r
+\r
+ AllEndPointsCount = RawMemoryRangeCount << 1;\r
+ AllEndPointsInclusive = calloc (AllEndPointsCount, sizeof (UINT64));\r
+ AllRangePiecesCountMax = RawMemoryRangeCount * 3 + 1;\r
+ AllRangePieces = calloc (AllRangePiecesCountMax, sizeof (MTRR_MEMORY_RANGE));\r
+ CollectEndpoints (AllEndPointsInclusive, &AllEndPointsCount, RawMemoryRanges, RawMemoryRangeCount);\r
+\r
+ for (Index = 0, AllRangePiecesCountActual = 0; Index < AllEndPointsCount - 1; Index++) {\r
+ OverlapBitFlag1 = GetOverlapBitFlag (RawMemoryRanges, RawMemoryRangeCount, AllEndPointsInclusive[Index]);\r
+ OverlapBitFlag2 = GetOverlapBitFlag (RawMemoryRanges, RawMemoryRangeCount, AllEndPointsInclusive[Index + 1]);\r
+ OverlapFlagRelation = CheckOverlapBitFlagsRelation (OverlapBitFlag1, OverlapBitFlag2);\r
+ switch (OverlapFlagRelation) {\r
+ case 0: // [1, 2]\r
+ AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];\r
+ AllRangePieces[AllRangePiecesCountActual].Length = AllEndPointsInclusive[Index + 1] - AllEndPointsInclusive[Index] + 1;\r
+ AllRangePiecesCountActual++;\r
+ break;\r
+ case 1: // [1, 2)\r
+ AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];\r
+ AllRangePieces[AllRangePiecesCountActual].Length = (AllEndPointsInclusive[Index + 1] - 1) - AllEndPointsInclusive[Index] + 1;\r
+ AllRangePiecesCountActual++;\r
+ break;\r
+ case 2: // (1, 2]\r
+ AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index] + 1;\r
+ AllRangePieces[AllRangePiecesCountActual].Length = AllEndPointsInclusive[Index + 1] - (AllEndPointsInclusive[Index] + 1) + 1;\r
+ AllRangePiecesCountActual++;\r
+\r
+ if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRangePieces, AllRangePiecesCountActual)) {\r
+ AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];\r
+ AllRangePieces[AllRangePiecesCountActual].Length = 1;\r
+ AllRangePiecesCountActual++;\r
+ }\r
+ break;\r
+ case 3: // (1, 2)\r
+ AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index] + 1;\r
+ AllRangePieces[AllRangePiecesCountActual].Length = (AllEndPointsInclusive[Index + 1] - 1) - (AllEndPointsInclusive[Index] + 1) + 1;\r
+ if (AllRangePieces[AllRangePiecesCountActual].Length == 0) // Only in case 3 can exists Length=0, we should skip such "segment".\r
+ break;\r
+ AllRangePiecesCountActual++;\r
+ if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRangePieces, AllRangePiecesCountActual)) {\r
+ AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];\r
+ AllRangePieces[AllRangePiecesCountActual].Length = 1;\r
+ AllRangePiecesCountActual++;\r
+ }\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+ }\r
+\r
+ for (Index = 0; Index < AllRangePiecesCountActual; Index++) {\r
+ DetermineMemoryCacheType (DefaultType, &AllRangePieces[Index], RawMemoryRanges, RawMemoryRangeCount);\r
+ }\r
+\r
+ CompactAndExtendEffectiveMtrrMemoryRanges (DefaultType, PhysicalAddressBits, &AllRangePieces, &AllRangePiecesCountActual);\r
+ ASSERT (*MemoryRangeCount >= AllRangePiecesCountActual);\r
+ memcpy (MemoryRanges, AllRangePieces, AllRangePiecesCountActual * sizeof (MTRR_MEMORY_RANGE));\r
+ *MemoryRangeCount = AllRangePiecesCountActual;\r
+\r
+ free (AllEndPointsInclusive);\r
+ free (AllRangePieces);\r
+}\r