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