From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by mx.groups.io with SMTP id smtpd.web11.4115.1595904078091577094 for ; Mon, 27 Jul 2020 19:41:18 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 192.55.52.151, mailfrom: ray.ni@intel.com) IronPort-SDR: ideeQ8lHTDf6KbNQMr9JJPK3mdLLjDdUakXw04JGh93PKFLGisrTm7X/RHprPQpqcShFhLwHVm nBYFncFrDjBA== X-IronPort-AV: E=McAfee;i="6000,8403,9695"; a="131206409" X-IronPort-AV: E=Sophos;i="5.75,404,1589266800"; d="scan'208";a="131206409" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Jul 2020 19:41:16 -0700 IronPort-SDR: IaEV7nH2rIZL6O+Gl/tc2+HIdV5BIpd5/MHki7k9TfmpGH4z8i3qlkPzOXh2e1AFX7DQ3riFNP dlbeVdNyYCWA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.75,404,1589266800"; d="scan'208";a="364337719" Received: from fmsmsx106.amr.corp.intel.com ([10.18.124.204]) by orsmga001.jf.intel.com with ESMTP; 27 Jul 2020 19:41:16 -0700 Received: from fmsmsx113.amr.corp.intel.com (10.18.116.7) by FMSMSX106.amr.corp.intel.com (10.18.124.204) with Microsoft SMTP Server (TLS) id 14.3.439.0; Mon, 27 Jul 2020 19:41:15 -0700 Received: from shsmsx151.ccr.corp.intel.com (10.239.6.50) by FMSMSX113.amr.corp.intel.com (10.18.116.7) with Microsoft SMTP Server (TLS) id 14.3.439.0; Mon, 27 Jul 2020 19:41:14 -0700 Received: from shsmsx104.ccr.corp.intel.com ([169.254.5.135]) by SHSMSX151.ccr.corp.intel.com ([169.254.3.49]) with mapi id 14.03.0439.000; Tue, 28 Jul 2020 10:41:09 +0800 From: "Ni, Ray" To: "devel@edk2.groups.io" , "Ni, Ray" CC: "Kinney, Michael D" , "Shao, Ming" , "Dong, Eric" , Laszlo Ersek , Sean Brogan , Bret Barkelew , "Yao, Jiewen" Subject: Re: [edk2-devel] [PATCH v3] UefiCpuPkg/MtrrLib/UnitTest: Add host based unit test Thread-Topic: [edk2-devel] [PATCH v3] UefiCpuPkg/MtrrLib/UnitTest: Add host based unit test Thread-Index: AQHWZIcvCN+cC4kWs0OKOtxYKHGteqkcRvmg Date: Tue, 28 Jul 2020 02:41:08 +0000 Message-ID: <734D49CCEBEEF84792F5B80ED585239D5C62D380@SHSMSX104.ccr.corp.intel.com> References: <1625C9C070741AB7.9177@groups.io> In-Reply-To: <1625C9C070741AB7.9177@groups.io> Accept-Language: en-US, zh-CN X-MS-Has-Attach: X-MS-TNEF-Correlator: dlp-product: dlpe-windows dlp-version: 11.2.0.6 dlp-reaction: no-action x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Return-Path: ray.ni@intel.com Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Mike, Eric, Laszlo, Sorry I just found that the v2 patch cannot pass the CI test because the ya= ml file is not updated to allow some modules depend on UnitTestFrameworkPkg= . So, this v3 patch doesn't change the other files but only yaml files compar= ing to v2. I cannot separate the yaml change to a separate patch because that will sti= ll break the CI. But, please just review the yaml part. I guarantee that no changes were mad= e to non-yaml files. I also added the unit test build/run to CI build step, following what MdePk= g/MdeModulePkg did. Thanks, Ray > -----Original Message----- > From: devel@edk2.groups.io On Behalf Of Ni, Ray > Sent: Tuesday, July 28, 2020 10:30 AM > To: devel@edk2.groups.io > Cc: Kinney, Michael D ; Shao, Ming ; Dong, Eric > ; Laszlo Ersek ; Sean Brogan ; Bret Barkelew > ; Yao, Jiewen > Subject: [edk2-devel] [PATCH v3] UefiCpuPkg/MtrrLib/UnitTest: Add host ba= sed unit test >=20 > Add host based unit tests for the MtrrLib services. > The BaseLib services AsmCpuid(), AsmReadMsr64(), and > AsmWriteMsr64() are hooked and provide simple emulation > of the CPUID leafs and MSRs required by the MtrrLib to > run as a host based unit test. >=20 > Test cases are developed for each of the API. >=20 > For the most important APIs MtrrSetMemoryAttributesInMtrrSettings() > and MtrrSetMemoryAttributeInMtrrSettings(), random inputs are > generated and fed to the APIs to make sure the implementation is > good. The test application accepts an optional parameter which > specifies how many iterations of feeding random inputs to the two > APIs. The overall number of test cases increases when the iteration > increases. Default iteration is 10 when no parameter is specified. >=20 > Signed-off-by: Ray Ni > Signed-off-by: Michael D Kinney > Signed-off-by: Ming Shao > Cc: Michael D Kinney > Cc: Eric Dong > Cc: Laszlo Ersek > Cc: Ming Shao > Cc: Sean Brogan > Cc: Bret Barkelew > Cc: Jiewen Yao > --- > .../MtrrLib/UnitTest/MtrrLibUnitTest.c | 1140 +++++++++++++++++ > .../MtrrLib/UnitTest/MtrrLibUnitTest.h | 171 +++ > .../MtrrLib/UnitTest/MtrrLibUnitTestHost.inf | 39 + > UefiCpuPkg/Library/MtrrLib/UnitTest/Support.c | 913 +++++++++++++ > UefiCpuPkg/Test/UefiCpuPkgHostTest.dsc | 31 + > UefiCpuPkg/UefiCpuPkg.ci.yaml | 12 +- > 6 files changed, 2305 insertions(+), 1 deletion(-) > create mode 100644 UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.c > create mode 100644 UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.h > create mode 100644 UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTestHo= st.inf > create mode 100644 UefiCpuPkg/Library/MtrrLib/UnitTest/Support.c > create mode 100644 UefiCpuPkg/Test/UefiCpuPkgHostTest.dsc >=20 > diff --git a/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.c > b/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.c > new file mode 100644 > index 0000000000..2eac41fc74 > --- /dev/null > +++ b/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.c > @@ -0,0 +1,1140 @@ > +/** @file >=20 > + Unit tests of the MtrrLib instance of the MtrrLib class >=20 > + >=20 > + Copyright (c) 2020, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > + >=20 > +**/ >=20 > + >=20 > +#include "MtrrLibUnitTest.h" >=20 > + >=20 > +STATIC CONST MTRR_LIB_SYSTEM_PARAMETER mDefaultSystemParameter =3D { >=20 > + 42, TRUE, TRUE, CacheUncacheable, 12 >=20 > +}; >=20 > + >=20 > +STATIC MTRR_LIB_SYSTEM_PARAMETER mSystemParameters[] =3D { >=20 > + { 38, TRUE, TRUE, CacheUncacheable, 12 }, >=20 > + { 38, TRUE, TRUE, CacheWriteBack, 12 }, >=20 > + { 38, TRUE, TRUE, CacheWriteThrough, 12 }, >=20 > + { 38, TRUE, TRUE, CacheWriteProtected, 12 }, >=20 > + { 38, TRUE, TRUE, CacheWriteCombining, 12 }, >=20 > + >=20 > + { 42, TRUE, TRUE, CacheUncacheable, 12 }, >=20 > + { 42, TRUE, TRUE, CacheWriteBack, 12 }, >=20 > + { 42, TRUE, TRUE, CacheWriteThrough, 12 }, >=20 > + { 42, TRUE, TRUE, CacheWriteProtected, 12 }, >=20 > + { 42, TRUE, TRUE, CacheWriteCombining, 12 }, >=20 > + >=20 > + { 48, TRUE, TRUE, CacheUncacheable, 12 }, >=20 > + { 48, TRUE, TRUE, CacheWriteBack, 12 }, >=20 > + { 48, TRUE, TRUE, CacheWriteThrough, 12 }, >=20 > + { 48, TRUE, TRUE, CacheWriteProtected, 12 }, >=20 > + { 48, TRUE, TRUE, CacheWriteCombining, 12 }, >=20 > +}; >=20 > + >=20 > +UINT32 mFixedMtrrsIndex[] =3D { >=20 > + MSR_IA32_MTRR_FIX64K_00000, >=20 > + MSR_IA32_MTRR_FIX16K_80000, >=20 > + MSR_IA32_MTRR_FIX16K_A0000, >=20 > + MSR_IA32_MTRR_FIX4K_C0000, >=20 > + MSR_IA32_MTRR_FIX4K_C8000, >=20 > + MSR_IA32_MTRR_FIX4K_D0000, >=20 > + MSR_IA32_MTRR_FIX4K_D8000, >=20 > + MSR_IA32_MTRR_FIX4K_E0000, >=20 > + MSR_IA32_MTRR_FIX4K_E8000, >=20 > + MSR_IA32_MTRR_FIX4K_F0000, >=20 > + MSR_IA32_MTRR_FIX4K_F8000 >=20 > +}; >=20 > +STATIC_ASSERT ( >=20 > + (ARRAY_SIZE (mFixedMtrrsIndex) =3D=3D MTRR_NUMBER_OF_FIXED_MTRR), >=20 > + "gFixedMtrrIndex does NOT contain all the fixed MTRRs!" >=20 > + ); >=20 > + >=20 > +// >=20 > +// Context structure to be used for most of the test cases. >=20 > +// >=20 > +typedef struct { >=20 > + CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter; >=20 > +} MTRR_LIB_TEST_CONTEXT; >=20 > + >=20 > +// >=20 > +// Context structure to be used for GetFirmwareVariableMtrrCount() test. >=20 > +// >=20 > +typedef struct { >=20 > + UINT32 NumberOfReservedVariableMtrrs; >=20 > + CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter; >=20 > +} MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT; >=20 > + >=20 > +STATIC CHAR8 *mCacheDescription[] =3D { "UC", "WC", "N/A", "N/A", "WT", = "WP", "WB" }; >=20 > + >=20 > +/** >=20 > + Compare the actual memory ranges against expected memory ranges and re= turn PASS when they match. >=20 > + >=20 > + @param ExpectedMemoryRanges Expected memory ranges. >=20 > + @param ExpectedMemoryRangeCount Count of expected memory ranges. >=20 > + @param ActualRanges Actual memory ranges. >=20 > + @param ActualRangeCount Count of actual memory ranges. >=20 > + >=20 > + @retval UNIT_TEST_PASSED Test passed. >=20 > + @retval others Test failed. >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +VerifyMemoryRanges ( >=20 > + IN MTRR_MEMORY_RANGE *ExpectedMemoryRanges, >=20 > + IN UINTN ExpectedMemoryRangeCount, >=20 > + IN MTRR_MEMORY_RANGE *ActualRanges, >=20 > + IN UINTN ActualRangeCount >=20 > + ) >=20 > +{ >=20 > + UINTN Index; >=20 > + UT_ASSERT_EQUAL (ExpectedMemoryRangeCount, ActualRangeCount); >=20 > + for (Index =3D 0; Index < ExpectedMemoryRangeCount; Index++) { >=20 > + UT_ASSERT_EQUAL (ExpectedMemoryRanges[Index].BaseAddress, ActualRang= es[Index].BaseAddress); >=20 > + UT_ASSERT_EQUAL (ExpectedMemoryRanges[Index].Length, ActualRanges[In= dex].Length); >=20 > + UT_ASSERT_EQUAL (ExpectedMemoryRanges[Index].Type, ActualRanges[Inde= x].Type); >=20 > + } >=20 > + >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Dump the memory ranges. >=20 > + >=20 > + @param Ranges Memory ranges to dump. >=20 > + @param RangeCount Count of memory ranges. >=20 > +**/ >=20 > +VOID >=20 > +DumpMemoryRanges ( >=20 > + MTRR_MEMORY_RANGE *Ranges, >=20 > + UINTN RangeCount >=20 > + ) >=20 > +{ >=20 > + UINTN Index; >=20 > + for (Index =3D 0; Index < RangeCount; Index++) { >=20 > + UT_LOG_INFO ("\t{ 0x%016llx, 0x%016llx, %a },\n", Ranges[Index].Base= Address, Ranges[Index].Length, > mCacheDescription[Ranges[Index].Type]); >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > +**/ >=20 > + >=20 > +/** >=20 > + Generate random count of MTRRs for each cache type. >=20 > + >=20 > + @param TotalCount Total MTRR count. >=20 > + @param UcCount Return count of Uncacheable type. >=20 > + @param WtCount Return count of Write Through type. >=20 > + @param WbCount Return count of Write Back type. >=20 > + @param WpCount Return count of Write Protected type. >=20 > + @param WcCount Return count of Write Combining type. >=20 > +**/ >=20 > +VOID >=20 > +GenerateRandomMemoryTypeCombination ( >=20 > + IN UINT32 TotalCount, >=20 > + OUT UINT32 *UcCount, >=20 > + OUT UINT32 *WtCount, >=20 > + OUT UINT32 *WbCount, >=20 > + OUT UINT32 *WpCount, >=20 > + OUT UINT32 *WcCount >=20 > + ) >=20 > +{ >=20 > + UINTN Index; >=20 > + UINT32 TotalMtrrCount; >=20 > + UINT32 *CountPerType[5]; >=20 > + >=20 > + CountPerType[0] =3D UcCount; >=20 > + CountPerType[1] =3D WtCount; >=20 > + CountPerType[2] =3D WbCount; >=20 > + CountPerType[3] =3D WpCount; >=20 > + CountPerType[4] =3D WcCount; >=20 > + >=20 > + // >=20 > + // Initialize the count of each cache type to 0. >=20 > + // >=20 > + for (Index =3D 0; Index < ARRAY_SIZE (CountPerType); Index++) { >=20 > + *(CountPerType[Index]) =3D 0; >=20 > + } >=20 > + >=20 > + // >=20 > + // Pick a random count of MTRRs >=20 > + // >=20 > + TotalMtrrCount =3D Random32 (1, TotalCount); >=20 > + for (Index =3D 0; Index < TotalMtrrCount; Index++) { >=20 > + // >=20 > + // For each of them, pick a random cache type. >=20 > + // >=20 > + (*(CountPerType[Random32 (0, ARRAY_SIZE (CountPerType) - 1)]))++; >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Unit test of MtrrLib service MtrrSetMemoryAttribute() >=20 > + >=20 > + @param[in] Context Ignored >=20 > + >=20 > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test >=20 > + case was successful. >=20 > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . >=20 > + >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +UnitTestMtrrSetMemoryAttributesInMtrrSettings ( >=20 > + IN UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter; >=20 > + RETURN_STATUS Status; >=20 > + UINT32 UcCount; >=20 > + UINT32 WtCount; >=20 > + UINT32 WbCount; >=20 > + UINT32 WpCount; >=20 > + UINT32 WcCount; >=20 > + >=20 > + UINT32 MtrrIndex; >=20 > + UINT8 *Scratch; >=20 > + UINTN ScratchSize; >=20 > + MTRR_SETTINGS LocalMtrrs; >=20 > + >=20 > + MTRR_MEMORY_RANGE RawMtrrRange[MTRR_NUMBER_OF_VARIABLE_M= TRR]; >=20 > + MTRR_MEMORY_RANGE ExpectedMemoryRanges[MTRR_NUMBER_OF_FI= XED_MTRR * sizeof (UINT64) + 2 * > MTRR_NUMBER_OF_VARIABLE_MTRR + 1]; >=20 > + UINT32 ExpectedVariableMtrrUsage; >=20 > + UINTN ExpectedMemoryRangesCount; >=20 > + >=20 > + MTRR_MEMORY_RANGE ActualMemoryRanges[MTRR_NUMBER_OF_FIXE= D_MTRR * sizeof (UINT64) + 2 * > MTRR_NUMBER_OF_VARIABLE_MTRR + 1]; >=20 > + UINT32 ActualVariableMtrrUsage; >=20 > + UINTN ActualMemoryRangesCount; >=20 > + >=20 > + MTRR_SETTINGS *Mtrrs[2]; >=20 > + >=20 > + SystemParameter =3D (MTRR_LIB_SYSTEM_PARAMETER *) Context; >=20 > + GenerateRandomMemoryTypeCombination ( >=20 > + SystemParameter->VariableMtrrCount - PatchPcdGet32 (PcdCpuNumberOfRe= servedVariableMtrrs), >=20 > + &UcCount, &WtCount, &WbCount, &WpCount, &WcCount >=20 > + ); >=20 > + GenerateValidAndConfigurableMtrrPairs ( >=20 > + SystemParameter->PhysicalAddressBits, RawMtrrRange, >=20 > + UcCount, WtCount, WbCount, WpCount, WcCount >=20 > + ); >=20 > + >=20 > + ExpectedVariableMtrrUsage =3D UcCount + WtCount + WbCount + WpCount + = WcCount; >=20 > + ExpectedMemoryRangesCount =3D ARRAY_SIZE (ExpectedMemoryRanges); >=20 > + GetEffectiveMemoryRanges ( >=20 > + SystemParameter->DefaultCacheType, >=20 > + SystemParameter->PhysicalAddressBits, >=20 > + RawMtrrRange, ExpectedVariableMtrrUsage, >=20 > + ExpectedMemoryRanges, &ExpectedMemoryRangesCount >=20 > + ); >=20 > + >=20 > + UT_LOG_INFO ( >=20 > + "Total MTRR [%d]: UC=3D%d, WT=3D%d, WB=3D%d, WP=3D%d, WC=3D%d\n", >=20 > + ExpectedVariableMtrrUsage, UcCount, WtCount, WbCount, WpCount, WcCou= nt >=20 > + ); >=20 > + UT_LOG_INFO ("--- Expected Memory Ranges [%d] ---\n", ExpectedMemoryRa= ngesCount); >=20 > + DumpMemoryRanges (ExpectedMemoryRanges, ExpectedMemoryRangesCount); >=20 > + >=20 > + // >=20 > + // Default cache type is always an INPUT >=20 > + // >=20 > + ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs)); >=20 > + LocalMtrrs.MtrrDefType =3D MtrrGetDefaultMemoryType (); >=20 > + ScratchSize =3D SCRATCH_BUFFER_SIZE; >=20 > + Mtrrs[0] =3D &LocalMtrrs; >=20 > + Mtrrs[1] =3D NULL; >=20 > + >=20 > + for (MtrrIndex =3D 0; MtrrIndex < ARRAY_SIZE (Mtrrs); MtrrIndex++) { >=20 > + Scratch =3D calloc (ScratchSize, sizeof (UINT8)); >=20 > + Status =3D MtrrSetMemoryAttributesInMtrrSettings (Mtrrs[MtrrIndex], = Scratch, &ScratchSize, ExpectedMemoryRanges, > ExpectedMemoryRangesCount); >=20 > + if (Status =3D=3D RETURN_BUFFER_TOO_SMALL) { >=20 > + Scratch =3D realloc (Scratch, ScratchSize); >=20 > + Status =3D MtrrSetMemoryAttributesInMtrrSettings (Mtrrs[MtrrIndex]= , Scratch, &ScratchSize, ExpectedMemoryRanges, > ExpectedMemoryRangesCount); >=20 > + } >=20 > + UT_ASSERT_STATUS_EQUAL (Status, RETURN_SUCCESS); >=20 > + >=20 > + if (Mtrrs[MtrrIndex] =3D=3D NULL) { >=20 > + ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs)); >=20 > + MtrrGetAllMtrrs (&LocalMtrrs); >=20 > + } >=20 > + ActualMemoryRangesCount =3D ARRAY_SIZE (ActualMemoryRanges); >=20 > + CollectTestResult ( >=20 > + SystemParameter->DefaultCacheType, SystemParameter->PhysicalAddres= sBits, SystemParameter->VariableMtrrCount, >=20 > + &LocalMtrrs, ActualMemoryRanges, &ActualMemoryRangesCount, &Actual= VariableMtrrUsage >=20 > + ); >=20 > + >=20 > + UT_LOG_INFO ("--- Actual Memory Ranges [%d] ---\n", ActualMemoryRang= esCount); >=20 > + DumpMemoryRanges (ActualMemoryRanges, ActualMemoryRangesCount); >=20 > + VerifyMemoryRanges (ExpectedMemoryRanges, ExpectedMemoryRangesCount,= ActualMemoryRanges, > ActualMemoryRangesCount); >=20 > + UT_ASSERT_TRUE (ExpectedVariableMtrrUsage >=3D ActualVariableMtrrUsa= ge); >=20 > + >=20 > + ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs)); >=20 > + } >=20 > + >=20 > + free (Scratch); >=20 > + >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Test routine to check whether invalid base/size can be rejected. >=20 > + >=20 > + @param Context Pointer to MTRR_LIB_SYSTEM_PARAMETER. >=20 > + >=20 > + @return Test status. >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +UnitTestInvalidMemoryLayouts ( >=20 > + IN UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter; >=20 > + MTRR_MEMORY_RANGE Ranges[MTRR_NUMBER_OF_VARIABLE_MTRR * = 2 + 1]; >=20 > + UINTN RangeCount; >=20 > + UINT64 MaxAddress; >=20 > + UINT32 Index; >=20 > + UINT64 BaseAddress; >=20 > + UINT64 Length; >=20 > + RETURN_STATUS Status; >=20 > + UINTN ScratchSize; >=20 > + >=20 > + SystemParameter =3D (MTRR_LIB_SYSTEM_PARAMETER *) Context; >=20 > + >=20 > + RangeCount =3D Random32 (1, ARRAY_SIZE (Ranges)); >=20 > + MaxAddress =3D 1ull << SystemParameter->PhysicalAddressBits; >=20 > + >=20 > + for (Index =3D 0; Index < RangeCount; Index++) { >=20 > + do { >=20 > + BaseAddress =3D Random64 (0, MaxAddress); >=20 > + Length =3D Random64 (1, MaxAddress - BaseAddress); >=20 > + } while (((BaseAddress & 0xFFF) =3D=3D 0) || ((Length & 0xFFF) =3D= =3D 0)); >=20 > + >=20 > + Ranges[Index].BaseAddress =3D BaseAddress; >=20 > + Ranges[Index].Length =3D Length; >=20 > + Ranges[Index].Type =3D GenerateRandomCacheType (); >=20 > + >=20 > + Status =3D MtrrSetMemoryAttribute ( >=20 > + Ranges[Index].BaseAddress, Ranges[Index].Length, Ranges[Index].Typ= e >=20 > + ); >=20 > + UT_ASSERT_TRUE (RETURN_ERROR (Status)); >=20 > + } >=20 > + >=20 > + ScratchSize =3D 0; >=20 > + Status =3D MtrrSetMemoryAttributesInMtrrSettings (NULL, NULL, &Scratch= Size, Ranges, RangeCount); >=20 > + UT_ASSERT_TRUE (RETURN_ERROR (Status)); >=20 > + >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unit test of MtrrLib service IsMtrrSupported() >=20 > + >=20 > + @param[in] Context Ignored >=20 > + >=20 > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test >=20 > + case was successful. >=20 > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . >=20 > + >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +UnitTestIsMtrrSupported ( >=20 > + IN UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + MTRR_LIB_SYSTEM_PARAMETER SystemParameter; >=20 > + MTRR_LIB_TEST_CONTEXT *LocalContext; >=20 > + >=20 > + LocalContext =3D (MTRR_LIB_TEST_CONTEXT *) Context; >=20 > + >=20 > + CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (Syst= emParameter)); >=20 > + // >=20 > + // MTRR capability off in CPUID leaf. >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D FALSE; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + UT_ASSERT_FALSE (IsMtrrSupported ()); >=20 > + >=20 > + // >=20 > + // MTRR capability on in CPUID leaf, but no variable or fixed MTRRs. >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D TRUE; >=20 > + SystemParameter.VariableMtrrCount =3D 0; >=20 > + SystemParameter.FixedMtrrSupported =3D FALSE; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + UT_ASSERT_FALSE (IsMtrrSupported ()); >=20 > + >=20 > + // >=20 > + // MTRR capability on in CPUID leaf, but no variable MTRRs. >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D TRUE; >=20 > + SystemParameter.VariableMtrrCount =3D 0; >=20 > + SystemParameter.FixedMtrrSupported =3D TRUE; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + UT_ASSERT_FALSE (IsMtrrSupported ()); >=20 > + >=20 > + // >=20 > + // MTRR capability on in CPUID leaf, but no fixed MTRRs. >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D TRUE; >=20 > + SystemParameter.VariableMtrrCount =3D 7; >=20 > + SystemParameter.FixedMtrrSupported =3D FALSE; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + UT_ASSERT_FALSE (IsMtrrSupported ()); >=20 > + >=20 > + // >=20 > + // MTRR capability on in CPUID leaf with both variable and fixed MTRRs= . >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D TRUE; >=20 > + SystemParameter.VariableMtrrCount =3D 7; >=20 > + SystemParameter.FixedMtrrSupported =3D TRUE; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + UT_ASSERT_TRUE (IsMtrrSupported ()); >=20 > + >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unit test of MtrrLib service GetVariableMtrrCount() >=20 > + >=20 > + @param[in] Context Ignored >=20 > + >=20 > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test >=20 > + case was successful. >=20 > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . >=20 > + >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +UnitTestGetVariableMtrrCount ( >=20 > + IN UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + UINT32 Result; >=20 > + MTRR_LIB_SYSTEM_PARAMETER SystemParameter; >=20 > + MTRR_LIB_TEST_CONTEXT *LocalContext; >=20 > + >=20 > + LocalContext =3D (MTRR_LIB_TEST_CONTEXT *) Context; >=20 > + >=20 > + CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (Syst= emParameter)); >=20 > + // >=20 > + // If MTRR capability off in CPUID leaf, then the count is always 0. >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D FALSE; >=20 > + for (SystemParameter.VariableMtrrCount =3D 1; SystemParameter.Variable= MtrrCount <=3D > MTRR_NUMBER_OF_VARIABLE_MTRR; SystemParameter.VariableMtrrCount++) { >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + Result =3D GetVariableMtrrCount (); >=20 > + UT_ASSERT_EQUAL (Result, 0); >=20 > + } >=20 > + >=20 > + // >=20 > + // Try all supported variable MTRR counts. >=20 > + // If variable MTRR count is > MTRR_NUMBER_OF_VARIABLE_MTRR, then an A= SSERT() >=20 > + // is generated. >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D TRUE; >=20 > + for (SystemParameter.VariableMtrrCount =3D 1; SystemParameter.Variable= MtrrCount <=3D > MTRR_NUMBER_OF_VARIABLE_MTRR; SystemParameter.VariableMtrrCount++) { >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + Result =3D GetVariableMtrrCount (); >=20 > + UT_ASSERT_EQUAL (Result, SystemParameter.VariableMtrrCount); >=20 > + } >=20 > + >=20 > + // >=20 > + // Expect ASSERT() if variable MTRR count is > MTRR_NUMBER_OF_VARIABLE= _MTRR >=20 > + // >=20 > + SystemParameter.VariableMtrrCount =3D MTRR_NUMBER_OF_VARIABLE_MTRR + 1= ; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + UT_EXPECT_ASSERT_FAILURE (GetVariableMtrrCount (), NULL); >=20 > + >=20 > + SystemParameter.MtrrSupported =3D TRUE; >=20 > + SystemParameter.VariableMtrrCount =3D MAX_UINT8; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + UT_EXPECT_ASSERT_FAILURE (GetVariableMtrrCount (), NULL); >=20 > + >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unit test of MtrrLib service GetFirmwareVariableMtrrCount() >=20 > + >=20 > + @param[in] Context Ignored >=20 > + >=20 > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test >=20 > + case was successful. >=20 > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . >=20 > + >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +UnitTestGetFirmwareVariableMtrrCount ( >=20 > + IN UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + UINT32 Result; >=20 > + UINT32 ReservedMtrrs; >=20 > + MTRR_LIB_SYSTEM_PARAMETER SystemParameter; >=20 > + MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *LocalContext; >=20 > + >=20 > + LocalContext =3D (MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *)= Context; >=20 > + >=20 > + CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (Syst= emParameter)); >=20 > + >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + // >=20 > + // Positive test cases for VCNT =3D 10 and Reserved PCD in range 0..10 >=20 > + // >=20 > + for (ReservedMtrrs =3D 0; ReservedMtrrs <=3D SystemParameter.VariableM= trrCount; ReservedMtrrs++) { >=20 > + PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, ReservedMtrrs); >=20 > + Result =3D GetFirmwareVariableMtrrCount (); >=20 > + UT_ASSERT_EQUAL (Result, SystemParameter.VariableMtrrCount - Reserve= dMtrrs); >=20 > + } >=20 > + >=20 > + // >=20 > + // Negative test cases when Reserved PCD is larger than VCNT >=20 > + // >=20 > + for (ReservedMtrrs =3D SystemParameter.VariableMtrrCount + 1; Reserved= Mtrrs <=3D 255; ReservedMtrrs++) { >=20 > + PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, ReservedMtrrs); >=20 > + Result =3D GetFirmwareVariableMtrrCount (); >=20 > + UT_ASSERT_EQUAL (Result, 0); >=20 > + } >=20 > + >=20 > + // >=20 > + // Negative test cases when Reserved PCD is larger than VCNT >=20 > + // >=20 > + PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, MAX_UINT32); >=20 > + Result =3D GetFirmwareVariableMtrrCount (); >=20 > + UT_ASSERT_EQUAL (Result, 0); >=20 > + >=20 > + // >=20 > + // Negative test case when MTRRs are not supported >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D FALSE; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, 2); >=20 > + Result =3D GetFirmwareVariableMtrrCount (); >=20 > + UT_ASSERT_EQUAL (Result, 0); >=20 > + >=20 > + // >=20 > + // Negative test case when Fixed MTRRs are not supported >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D TRUE; >=20 > + SystemParameter.FixedMtrrSupported =3D FALSE; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, 2); >=20 > + Result =3D GetFirmwareVariableMtrrCount (); >=20 > + UT_ASSERT_EQUAL (Result, 0); >=20 > + >=20 > + // >=20 > + // Expect ASSERT() if variable MTRR count is > MTRR_NUMBER_OF_VARIABLE= _MTRR >=20 > + // >=20 > + SystemParameter.FixedMtrrSupported =3D TRUE; >=20 > + SystemParameter.VariableMtrrCount =3D MTRR_NUMBER_OF_VARIABLE_MTRR + 1= ; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + UT_EXPECT_ASSERT_FAILURE (GetFirmwareVariableMtrrCount (), NULL); >=20 > + >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unit test of MtrrLib service MtrrGetMemoryAttribute() >=20 > + >=20 > + @param[in] Context Ignored >=20 > + >=20 > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test >=20 > + case was successful. >=20 > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . >=20 > + >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +UnitTestMtrrGetMemoryAttribute ( >=20 > + IN UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unit test of MtrrLib service MtrrGetFixedMtrr() >=20 > + >=20 > + @param[in] Context Ignored >=20 > + >=20 > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test >=20 > + case was successful. >=20 > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . >=20 > + >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +UnitTestMtrrGetFixedMtrr ( >=20 > + IN UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + MTRR_FIXED_SETTINGS *Result; >=20 > + MTRR_FIXED_SETTINGS ExpectedFixedSettings; >=20 > + MTRR_FIXED_SETTINGS FixedSettings; >=20 > + UINTN Index; >=20 > + UINTN MsrIndex; >=20 > + UINTN ByteIndex; >=20 > + UINT64 MsrValue; >=20 > + MTRR_LIB_SYSTEM_PARAMETER SystemParameter; >=20 > + MTRR_LIB_TEST_CONTEXT *LocalContext; >=20 > + >=20 > + LocalContext =3D (MTRR_LIB_TEST_CONTEXT *) Context; >=20 > + >=20 > + CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (Syst= emParameter)); >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + // >=20 > + // Set random cache type to different ranges under 1MB and make sure >=20 > + // the fixed MTRR settings are expected. >=20 > + // Try 100 times. >=20 > + // >=20 > + for (Index =3D 0; Index < 100; Index++) { >=20 > + for (MsrIndex =3D 0; MsrIndex < ARRAY_SIZE (mFixedMtrrsIndex); MsrIn= dex++) { >=20 > + MsrValue =3D 0; >=20 > + for (ByteIndex =3D 0; ByteIndex < sizeof (UINT64); ByteIndex++) { >=20 > + MsrValue =3D MsrValue | LShiftU64 (GenerateRandomCacheType (), B= yteIndex * 8); >=20 > + } >=20 > + ExpectedFixedSettings.Mtrr[MsrIndex] =3D MsrValue; >=20 > + AsmWriteMsr64 (mFixedMtrrsIndex[MsrIndex], MsrValue); >=20 > + } >=20 > + >=20 > + Result =3D MtrrGetFixedMtrr (&FixedSettings); >=20 > + UT_ASSERT_EQUAL (Result, &FixedSettings); >=20 > + UT_ASSERT_MEM_EQUAL (&FixedSettings, &ExpectedFixedSettings, sizeof = (FixedSettings)); >=20 > + } >=20 > + >=20 > + // >=20 > + // Negative test case when MTRRs are not supported >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D FALSE; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + >=20 > + ZeroMem (&FixedSettings, sizeof (FixedSettings)); >=20 > + ZeroMem (&ExpectedFixedSettings, sizeof (ExpectedFixedSettings)); >=20 > + Result =3D MtrrGetFixedMtrr (&FixedSettings); >=20 > + UT_ASSERT_EQUAL (Result, &FixedSettings); >=20 > + UT_ASSERT_MEM_EQUAL (&ExpectedFixedSettings, &FixedSettings, sizeof (E= xpectedFixedSettings)); >=20 > + >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unit test of MtrrLib service MtrrGetAllMtrrs() >=20 > + >=20 > + @param[in] Context Ignored >=20 > + >=20 > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test >=20 > + case was successful. >=20 > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . >=20 > + >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +UnitTestMtrrGetAllMtrrs ( >=20 > + IN UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + MTRR_SETTINGS *Result; >=20 > + MTRR_SETTINGS Mtrrs; >=20 > + MTRR_SETTINGS ExpectedMtrrs; >=20 > + MTRR_VARIABLE_SETTING VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR]; >=20 > + UINT32 Index; >=20 > + MTRR_LIB_SYSTEM_PARAMETER SystemParameter; >=20 > + MTRR_LIB_TEST_CONTEXT *LocalContext; >=20 > + >=20 > + LocalContext =3D (MTRR_LIB_TEST_CONTEXT *) Context; >=20 > + >=20 > + CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (Syst= emParameter)); >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + >=20 > + for (Index =3D 0; Index < SystemParameter.VariableMtrrCount; Index++) = { >=20 > + GenerateRandomMtrrPair (SystemParameter.PhysicalAddressBits, Generat= eRandomCacheType (), &VariableMtrr[Index], > NULL); >=20 > + AsmWriteMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1), VariableMtrr[= Index].Base); >=20 > + AsmWriteMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1), VariableMtrr[= Index].Mask); >=20 > + } >=20 > + Result =3D MtrrGetAllMtrrs (&Mtrrs); >=20 > + UT_ASSERT_EQUAL (Result, &Mtrrs); >=20 > + UT_ASSERT_MEM_EQUAL (Mtrrs.Variables.Mtrr, VariableMtrr, sizeof (MTRR_= VARIABLE_SETTING) * > SystemParameter.VariableMtrrCount); >=20 > + >=20 > + // >=20 > + // Negative test case when MTRRs are not supported >=20 > + // >=20 > + ZeroMem (&ExpectedMtrrs, sizeof (ExpectedMtrrs)); >=20 > + ZeroMem (&Mtrrs, sizeof (Mtrrs)); >=20 > + >=20 > + SystemParameter.MtrrSupported =3D FALSE; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + Result =3D MtrrGetAllMtrrs (&Mtrrs); >=20 > + UT_ASSERT_EQUAL (Result, &Mtrrs); >=20 > + UT_ASSERT_MEM_EQUAL (&ExpectedMtrrs, &Mtrrs, sizeof (ExpectedMtrrs)); >=20 > + >=20 > + // >=20 > + // Expect ASSERT() if variable MTRR count is > MTRR_NUMBER_OF_VARIABLE= _MTRR >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D TRUE; >=20 > + SystemParameter.VariableMtrrCount =3D MTRR_NUMBER_OF_VARIABLE_MTRR + 1= ; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + UT_EXPECT_ASSERT_FAILURE (MtrrGetAllMtrrs (&Mtrrs), NULL); >=20 > + >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unit test of MtrrLib service MtrrSetAllMtrrs() >=20 > + >=20 > + @param[in] Context Ignored >=20 > + >=20 > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test >=20 > + case was successful. >=20 > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . >=20 > + >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +UnitTestMtrrSetAllMtrrs ( >=20 > + IN UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + MTRR_SETTINGS *Result; >=20 > + MTRR_SETTINGS Mtrrs; >=20 > + UINT32 Index; >=20 > + MSR_IA32_MTRR_DEF_TYPE_REGISTER Default; >=20 > + MTRR_LIB_SYSTEM_PARAMETER SystemParameter; >=20 > + MTRR_LIB_TEST_CONTEXT *LocalContext; >=20 > + >=20 > + LocalContext =3D (MTRR_LIB_TEST_CONTEXT *) Context; >=20 > + >=20 > + CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (Syst= emParameter)); >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + >=20 > + Default.Uint64 =3D 0; >=20 > + Default.Bits.E =3D 1; >=20 > + Default.Bits.FE =3D 1; >=20 > + Default.Bits.Type =3D GenerateRandomCacheType (); >=20 > + >=20 > + ZeroMem (&Mtrrs, sizeof (Mtrrs)); >=20 > + Mtrrs.MtrrDefType =3D Default.Uint64; >=20 > + for (Index =3D 0; Index < SystemParameter.VariableMtrrCount; Index++) = { >=20 > + GenerateRandomMtrrPair (SystemParameter.PhysicalAddressBits, Generat= eRandomCacheType (), > &Mtrrs.Variables.Mtrr[Index], NULL); >=20 > + } >=20 > + Result =3D MtrrSetAllMtrrs (&Mtrrs); >=20 > + UT_ASSERT_EQUAL (Result, &Mtrrs); >=20 > + >=20 > + UT_ASSERT_EQUAL (AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE), Mtrrs.MtrrDefT= ype); >=20 > + for (Index =3D 0; Index < SystemParameter.VariableMtrrCount; Index++) = { >=20 > + UT_ASSERT_EQUAL (AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1= )), Mtrrs.Variables.Mtrr[Index].Base); >=20 > + UT_ASSERT_EQUAL (AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1= )), Mtrrs.Variables.Mtrr[Index].Mask); >=20 > + } >=20 > + >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unit test of MtrrLib service MtrrGetMemoryAttributeInVariableMtrr() >=20 > + >=20 > + @param[in] Context Ignored >=20 > + >=20 > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test >=20 > + case was successful. >=20 > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . >=20 > + >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +UnitTestMtrrGetMemoryAttributeInVariableMtrr ( >=20 > + IN UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + MTRR_LIB_TEST_CONTEXT *LocalContext; >=20 > + MTRR_LIB_SYSTEM_PARAMETER SystemParameter; >=20 > + UINT32 Result; >=20 > + MTRR_VARIABLE_SETTING VariableSetting[MTRR_NUMBER_OF_VARIABL= E_MTRR]; >=20 > + VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_M= TRR]; >=20 > + UINT64 ValidMtrrBitsMask; >=20 > + UINT64 ValidMtrrAddressMask; >=20 > + UINT32 Index; >=20 > + MSR_IA32_MTRR_PHYSBASE_REGISTER Base; >=20 > + MSR_IA32_MTRR_PHYSMASK_REGISTER Mask; >=20 > + >=20 > + LocalContext =3D (MTRR_LIB_TEST_CONTEXT *) Context; >=20 > + >=20 > + CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (Syst= emParameter)); >=20 > + >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + >=20 > + ValidMtrrBitsMask =3D (1ull << SystemParameter.PhysicalAddressBits)= - 1; >=20 > + ValidMtrrAddressMask =3D ValidMtrrBitsMask & 0xfffffffffffff000ULL; >=20 > + >=20 > + for (Index =3D 0; Index < SystemParameter.VariableMtrrCount; Index++) = { >=20 > + GenerateRandomMtrrPair (SystemParameter.PhysicalAddressBits, Generat= eRandomCacheType (), > &VariableSetting[Index], NULL); >=20 > + AsmWriteMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1), VariableSetti= ng[Index].Base); >=20 > + AsmWriteMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1), VariableSetti= ng[Index].Mask); >=20 > + } >=20 > + Result =3D MtrrGetMemoryAttributeInVariableMtrr (ValidMtrrBitsMask, Va= lidMtrrAddressMask, VariableMtrr); >=20 > + UT_ASSERT_EQUAL (Result, SystemParameter.VariableMtrrCount); >=20 > + >=20 > + for (Index =3D 0; Index < SystemParameter.VariableMtrrCount; Index++) = { >=20 > + Base.Uint64 =3D VariableMtrr[Index].BaseAddress; >=20 > + Base.Bits.Type =3D (UINT32) VariableMtrr[Index].Type; >=20 > + UT_ASSERT_EQUAL (Base.Uint64, VariableSetting[Index].Base); >=20 > + >=20 > + Mask.Uint64 =3D ~(VariableMtrr[Index].Length - 1) & ValidMtrrBits= Mask; >=20 > + Mask.Bits.V =3D 1; >=20 > + UT_ASSERT_EQUAL (Mask.Uint64, VariableSetting[Index].Mask); >=20 > + } >=20 > + >=20 > + // >=20 > + // Negative test case when MTRRs are not supported >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D FALSE; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + Result =3D MtrrGetMemoryAttributeInVariableMtrr (ValidMtrrBitsMask, Va= lidMtrrAddressMask, VariableMtrr); >=20 > + UT_ASSERT_EQUAL (Result, 0); >=20 > + >=20 > + // >=20 > + // Expect ASSERT() if variable MTRR count is > MTRR_NUMBER_OF_VARIABLE= _MTRR >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D TRUE; >=20 > + SystemParameter.VariableMtrrCount =3D MTRR_NUMBER_OF_VARIABLE_MTRR + 1= ; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + UT_EXPECT_ASSERT_FAILURE (MtrrGetMemoryAttributeInVariableMtrr (ValidM= trrBitsMask, ValidMtrrAddressMask, > VariableMtrr), NULL); >=20 > + >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unit test of MtrrLib service MtrrDebugPrintAllMtrrs() >=20 > + >=20 > + @param[in] Context Ignored >=20 > + >=20 > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test >=20 > + case was successful. >=20 > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . >=20 > + >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +UnitTestMtrrDebugPrintAllMtrrs ( >=20 > + IN UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unit test of MtrrLib service MtrrGetDefaultMemoryType(). >=20 > + >=20 > + @param[in] Context Ignored >=20 > + >=20 > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test >=20 > + case was successful. >=20 > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . >=20 > + >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +UnitTestMtrrGetDefaultMemoryType ( >=20 > + IN UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + MTRR_LIB_TEST_CONTEXT *LocalContext; >=20 > + UINTN Index; >=20 > + MTRR_MEMORY_CACHE_TYPE Result; >=20 > + MTRR_LIB_SYSTEM_PARAMETER SystemParameter; >=20 > + MTRR_MEMORY_CACHE_TYPE CacheType[5]; >=20 > + >=20 > + CacheType[0] =3D CacheUncacheable; >=20 > + CacheType[1] =3D CacheWriteCombining; >=20 > + CacheType[2] =3D CacheWriteThrough; >=20 > + CacheType[3] =3D CacheWriteProtected; >=20 > + CacheType[4] =3D CacheWriteBack; >=20 > + >=20 > + LocalContext =3D (MTRR_LIB_TEST_CONTEXT *) Context; >=20 > + >=20 > + CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (Syst= emParameter)); >=20 > + // >=20 > + // If MTRRs are supported, then always return the cache type in the MS= R >=20 > + // MSR_IA32_MTRR_DEF_TYPE >=20 > + // >=20 > + for (Index =3D 0; Index < ARRAY_SIZE (CacheType); Index++) { >=20 > + SystemParameter.DefaultCacheType =3D CacheType[Index]; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + Result =3D MtrrGetDefaultMemoryType (); >=20 > + UT_ASSERT_EQUAL (Result, SystemParameter.DefaultCacheType); >=20 > + } >=20 > + >=20 > + // >=20 > + // If MTRRs are not supported, then always return CacheUncacheable >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D FALSE; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + Result =3D MtrrGetDefaultMemoryType (); >=20 > + UT_ASSERT_EQUAL (Result, CacheUncacheable); >=20 > + >=20 > + SystemParameter.MtrrSupported =3D TRUE; >=20 > + SystemParameter.FixedMtrrSupported =3D FALSE; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + Result =3D MtrrGetDefaultMemoryType (); >=20 > + UT_ASSERT_EQUAL (Result, CacheUncacheable); >=20 > + >=20 > + SystemParameter.MtrrSupported =3D TRUE; >=20 > + SystemParameter.FixedMtrrSupported =3D TRUE; >=20 > + SystemParameter.VariableMtrrCount =3D 0; >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + Result =3D MtrrGetDefaultMemoryType (); >=20 > + UT_ASSERT_EQUAL (Result, CacheUncacheable); >=20 > + >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unit test of MtrrLib service MtrrSetMemoryAttributeInMtrrSettings(). >=20 > + >=20 > + @param[in] Context Ignored >=20 > + >=20 > + @retval UNIT_TEST_PASSED The Unit test has completed and = the test >=20 > + case was successful. >=20 > + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed= . >=20 > + >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +UnitTestMtrrSetMemoryAttributeInMtrrSettings ( >=20 > + IN UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter; >=20 > + RETURN_STATUS Status; >=20 > + UINT32 UcCount; >=20 > + UINT32 WtCount; >=20 > + UINT32 WbCount; >=20 > + UINT32 WpCount; >=20 > + UINT32 WcCount; >=20 > + >=20 > + UINTN MtrrIndex; >=20 > + UINTN Index; >=20 > + MTRR_SETTINGS LocalMtrrs; >=20 > + >=20 > + MTRR_MEMORY_RANGE RawMtrrRange[MTRR_NUMBER_OF_VARIABLE_M= TRR]; >=20 > + MTRR_MEMORY_RANGE ExpectedMemoryRanges[MTRR_NUMBER_OF_FI= XED_MTRR * sizeof (UINT64) + 2 * > MTRR_NUMBER_OF_VARIABLE_MTRR + 1]; >=20 > + UINT32 ExpectedVariableMtrrUsage; >=20 > + UINTN ExpectedMemoryRangesCount; >=20 > + >=20 > + MTRR_MEMORY_RANGE ActualMemoryRanges[MTRR_NUMBER_OF_FIXE= D_MTRR * sizeof (UINT64) + 2 * > MTRR_NUMBER_OF_VARIABLE_MTRR + 1]; >=20 > + UINT32 ActualVariableMtrrUsage; >=20 > + UINTN ActualMemoryRangesCount; >=20 > + >=20 > + MTRR_SETTINGS *Mtrrs[2]; >=20 > + >=20 > + SystemParameter =3D (MTRR_LIB_SYSTEM_PARAMETER *) Context; >=20 > + GenerateRandomMemoryTypeCombination ( >=20 > + SystemParameter->VariableMtrrCount - PatchPcdGet32 (PcdCpuNumberOfRe= servedVariableMtrrs), >=20 > + &UcCount, &WtCount, &WbCount, &WpCount, &WcCount >=20 > + ); >=20 > + GenerateValidAndConfigurableMtrrPairs ( >=20 > + SystemParameter->PhysicalAddressBits, RawMtrrRange, >=20 > + UcCount, WtCount, WbCount, WpCount, WcCount >=20 > + ); >=20 > + >=20 > + ExpectedVariableMtrrUsage =3D UcCount + WtCount + WbCount + WpCount + = WcCount; >=20 > + ExpectedMemoryRangesCount =3D ARRAY_SIZE (ExpectedMemoryRanges); >=20 > + GetEffectiveMemoryRanges ( >=20 > + SystemParameter->DefaultCacheType, >=20 > + SystemParameter->PhysicalAddressBits, >=20 > + RawMtrrRange, ExpectedVariableMtrrUsage, >=20 > + ExpectedMemoryRanges, &ExpectedMemoryRangesCount >=20 > + ); >=20 > + >=20 > + UT_LOG_INFO ("--- Expected Memory Ranges [%d] ---\n", ExpectedMemoryRa= ngesCount); >=20 > + DumpMemoryRanges (ExpectedMemoryRanges, ExpectedMemoryRangesCount); >=20 > + // >=20 > + // Default cache type is always an INPUT >=20 > + // >=20 > + ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs)); >=20 > + LocalMtrrs.MtrrDefType =3D MtrrGetDefaultMemoryType (); >=20 > + Mtrrs[0] =3D &LocalMtrrs; >=20 > + Mtrrs[1] =3D NULL; >=20 > + >=20 > + for (MtrrIndex =3D 0; MtrrIndex < ARRAY_SIZE (Mtrrs); MtrrIndex++) { >=20 > + for (Index =3D 0; Index < ExpectedMemoryRangesCount; Index++) { >=20 > + Status =3D MtrrSetMemoryAttributeInMtrrSettings ( >=20 > + Mtrrs[MtrrIndex], >=20 > + ExpectedMemoryRanges[Index].BaseAddress, >=20 > + ExpectedMemoryRanges[Index].Length, >=20 > + ExpectedMemoryRanges[Index].Type >=20 > + ); >=20 > + UT_ASSERT_TRUE (Status =3D=3D RETURN_SUCCESS || Status =3D=3D RETU= RN_OUT_OF_RESOURCES || Status =3D=3D > RETURN_BUFFER_TOO_SMALL); >=20 > + if (Status =3D=3D RETURN_OUT_OF_RESOURCES || Status =3D=3D RETURN_= BUFFER_TOO_SMALL) { >=20 > + return UNIT_TEST_SKIPPED; >=20 > + } >=20 > + } >=20 > + >=20 > + if (Mtrrs[MtrrIndex] =3D=3D NULL) { >=20 > + ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs)); >=20 > + MtrrGetAllMtrrs (&LocalMtrrs); >=20 > + } >=20 > + ActualMemoryRangesCount =3D ARRAY_SIZE (ActualMemoryRanges); >=20 > + CollectTestResult ( >=20 > + SystemParameter->DefaultCacheType, SystemParameter->PhysicalAddres= sBits, SystemParameter->VariableMtrrCount, >=20 > + &LocalMtrrs, ActualMemoryRanges, &ActualMemoryRangesCount, &Actual= VariableMtrrUsage >=20 > + ); >=20 > + UT_LOG_INFO ("--- Actual Memory Ranges [%d] ---\n", ActualMemoryRang= esCount); >=20 > + DumpMemoryRanges (ActualMemoryRanges, ActualMemoryRangesCount); >=20 > + VerifyMemoryRanges (ExpectedMemoryRanges, ExpectedMemoryRangesCount,= ActualMemoryRanges, > ActualMemoryRangesCount); >=20 > + UT_ASSERT_TRUE (ExpectedVariableMtrrUsage >=3D ActualVariableMtrrUsa= ge); >=20 > + >=20 > + ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs)); >=20 > + } >=20 > + >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > + >=20 > +/** >=20 > + Prep routine for UnitTestGetFirmwareVariableMtrrCount(). >=20 > + >=20 > + @param Context Point to a UINT32 data to save the PcdCpuNumberOfReser= vedVariableMtrrs. >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +SavePcdValue ( >=20 > + UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *LocalContext; >=20 > + >=20 > + LocalContext =3D (MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *)= Context; >=20 > + LocalContext->NumberOfReservedVariableMtrrs =3D PatchPcdGet32 (PcdCpuN= umberOfReservedVariableMtrrs); >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Clean up routine for UnitTestGetFirmwareVariableMtrrCount(). >=20 > + >=20 > + @param Context Point to a UINT32 data to save the PcdCpuNumberOfReser= vedVariableMtrrs. >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +RestorePcdValue ( >=20 > + UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *LocalContext; >=20 > + >=20 > + LocalContext =3D (MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *)= Context; >=20 > + PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, LocalContext->Numb= erOfReservedVariableMtrrs); >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Initialize the unit test framework, suite, and unit tests for the >=20 > + ResetSystemLib and run the ResetSystemLib unit test. >=20 > + >=20 > + @param Iteration Iteration of testing MtrrSetMemoryAttri= buteInMtrrSettings >=20 > + and MtrrSetMemoryAttributesInMtrrSettin= gs using random inputs. >=20 > + >=20 > + @retval EFI_SUCCESS All test cases were dispatched. >=20 > + @retval EFI_OUT_OF_RESOURCES There are not enough resources availabl= e to >=20 > + initialize the unit tests. >=20 > +**/ >=20 > +STATIC >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +UnitTestingEntry ( >=20 > + UINTN Iteration >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + UNIT_TEST_FRAMEWORK_HANDLE Framework; >=20 > + UNIT_TEST_SUITE_HANDLE MtrrApiTests; >=20 > + UINTN Index; >=20 > + UINTN SystemIndex; >=20 > + MTRR_LIB_TEST_CONTEXT Context; >=20 > + MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT GetFirmwareVariableM= trrCountContext; >=20 > + >=20 > + Context.SystemParameter =3D &mDefaultSyste= mParameter; >=20 > + GetFirmwareVariableMtrrCountContext.SystemParameter =3D &mDefaultSyste= mParameter; >=20 > + Framework =3D NULL; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERS= ION)); >=20 > + >=20 > + // >=20 > + // Setup the test framework for running the tests. >=20 > + // >=20 > + Status =3D InitUnitTestFramework (&Framework, UNIT_TEST_APP_NAME, gEfi= CallerBaseName, UNIT_TEST_APP_VERSION); >=20 > + if (EFI_ERROR (Status)) { >=20 > + DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status =3D %r= \n", Status)); >=20 > + goto EXIT; >=20 > + } >=20 > + >=20 > + // >=20 > + // --------------Suite-----------Description--------------Name--------= --Function--------Pre---Post-------------------Context----------- >=20 > + // >=20 > + >=20 > + // >=20 > + // Populate the MtrrLib API Unit Test Suite. >=20 > + // >=20 > + Status =3D CreateUnitTestSuite (&MtrrApiTests, Framework, "MtrrLib API= Tests", "MtrrLib.MtrrLib", NULL, NULL); >=20 > + if (EFI_ERROR (Status)) { >=20 > + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for MtrrLib API = Tests\n")); >=20 > + Status =3D EFI_OUT_OF_RESOURCES; >=20 > + goto EXIT; >=20 > + } >=20 > + AddTestCase (MtrrApiTests, "Test IsMtrrSupported", = "MtrrSupported", > UnitTestIsMtrrSupported, NULL, NULL, &Context); >=20 > + AddTestCase (MtrrApiTests, "Test GetVariableMtrrCount", = "GetVariableMtrrCount", > UnitTestGetVariableMtrrCount, NULL, NULL, &Context); >=20 > + AddTestCase (MtrrApiTests, "Test GetFirmwareVariableMtrrCount", = "GetFirmwareVariableMtrrCount", > UnitTestGetFirmwareVariableMtrrCount, SavePcdValue, RestorePcdVal= ue, &GetFirmwareVariableMtrrCountContext); >=20 > + AddTestCase (MtrrApiTests, "Test MtrrGetMemoryAttribute", = "MtrrGetMemoryAttribute", > UnitTestMtrrGetMemoryAttribute, NULL, NULL, &Context); >=20 > + AddTestCase (MtrrApiTests, "Test MtrrGetFixedMtrr", = "MtrrGetFixedMtrr", > UnitTestMtrrGetFixedMtrr, NULL, NULL, &Context); >=20 > + AddTestCase (MtrrApiTests, "Test MtrrGetAllMtrrs", = "MtrrGetAllMtrrs", > UnitTestMtrrGetAllMtrrs, NULL, NULL, &Context); >=20 > + AddTestCase (MtrrApiTests, "Test MtrrSetAllMtrrs", = "MtrrSetAllMtrrs", UnitTestMtrrSetAllMtrrs, > NULL, NULL, &Context); >=20 > + AddTestCase (MtrrApiTests, "Test MtrrGetMemoryAttributeInVariableMtrr"= , "MtrrGetMemoryAttributeInVariableMtrr", > UnitTestMtrrGetMemoryAttributeInVariableMtrr, NULL, NULL, &Context); >=20 > + AddTestCase (MtrrApiTests, "Test MtrrDebugPrintAllMtrrs", = "MtrrDebugPrintAllMtrrs", > UnitTestMtrrDebugPrintAllMtrrs, NULL, NULL, &Context); >=20 > + AddTestCase (MtrrApiTests, "Test MtrrGetDefaultMemoryType", = "MtrrGetDefaultMemoryType", > UnitTestMtrrGetDefaultMemoryType, NULL, NULL, &Context); >=20 > + >=20 > + for (SystemIndex =3D 0; SystemIndex < ARRAY_SIZE (mSystemParameters); = SystemIndex++) { >=20 > + for (Index =3D 0; Index < Iteration; Index++) { >=20 > + AddTestCase (MtrrApiTests, "Test InvalidMemoryLayouts", = "InvalidMemoryLayouts", > UnitTestInvalidMemoryLayouts, InitializeMtrrRegs, NULL, = &mSystemParameters[SystemIndex]); >=20 > + AddTestCase (MtrrApiTests, "Test MtrrSetMemoryAttributeInMtrrSetti= ngs", "MtrrSetMemoryAttributeInMtrrSettings", > UnitTestMtrrSetMemoryAttributeInMtrrSettings, InitializeMtrrRegs, NULL, = &mSystemParameters[SystemIndex]); >=20 > + AddTestCase (MtrrApiTests, "Test MtrrSetMemoryAttributesInMtrrSett= ings", > "MtrrSetMemoryAttributesInMtrrSettings", UnitTestMtrrSetMemoryAttributesI= nMtrrSettings, InitializeMtrrRegs, NULL, > &mSystemParameters[SystemIndex]); >=20 > + } >=20 > + } >=20 > + // >=20 > + // Execute the tests. >=20 > + // >=20 > + srand ((unsigned int) time (NULL)); >=20 > + Status =3D RunAllTestSuites (Framework); >=20 > + >=20 > +EXIT: >=20 > + if (Framework !=3D NULL) { >=20 > + FreeUnitTestFramework (Framework); >=20 > + } >=20 > + >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + Standard POSIX C entry point for host based unit test execution. >=20 > + >=20 > + @param Argc Number of arguments. >=20 > + @param Argv Array of arguments. >=20 > + >=20 > + @return Test application exit code. >=20 > +**/ >=20 > +INT32 >=20 > +main ( >=20 > + INT32 Argc, >=20 > + CHAR8 *Argv[] >=20 > + ) >=20 > +{ >=20 > + UINTN Iteration; >=20 > + >=20 > + // >=20 > + // First parameter specifies the test iterations. >=20 > + // Default is 10. >=20 > + // >=20 > + Iteration =3D 10; >=20 > + if (Argc =3D=3D 2) { >=20 > + Iteration =3D atoi (Argv[1]); >=20 > + } >=20 > + return UnitTestingEntry (Iteration); >=20 > +} >=20 > diff --git a/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.h > b/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.h > new file mode 100644 > index 0000000000..25d4269589 > --- /dev/null > +++ b/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.h > @@ -0,0 +1,171 @@ > +/** @file >=20 > + >=20 > + Copyright (c) 2020, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > + >=20 > +**/ >=20 > + >=20 > +#ifndef _MTRR_SUPPORT_H_ >=20 > +#define _MTRR_SUPPORT_H_ >=20 > + >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +#define UNIT_TEST_APP_NAME "MtrrLib Unit Tests" >=20 > +#define UNIT_TEST_APP_VERSION "1.0" >=20 > + >=20 > +#define SCRATCH_BUFFER_SIZE SIZE_16KB >=20 > + >=20 > +typedef struct { >=20 > + UINT8 PhysicalAddressBits; >=20 > + BOOLEAN MtrrSupported; >=20 > + BOOLEAN FixedMtrrSupported; >=20 > + MTRR_MEMORY_CACHE_TYPE DefaultCacheType; >=20 > + UINT32 VariableMtrrCount; >=20 > +} MTRR_LIB_SYSTEM_PARAMETER; >=20 > + >=20 > +extern UINT32 mFixedMtrrsIndex[]; >=20 > + >=20 > +/** >=20 > + Initialize the MTRR registers. >=20 > + >=20 > + @param SystemParameter System parameter that controls the MTRR registe= rs initialization. >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +InitializeMtrrRegs ( >=20 > + IN MTRR_LIB_SYSTEM_PARAMETER *SystemParameter >=20 > + ); >=20 > + >=20 > +/** >=20 > + Return a random memory cache type. >=20 > +**/ >=20 > +MTRR_MEMORY_CACHE_TYPE >=20 > +GenerateRandomCacheType ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Generate random MTRRs. >=20 > + >=20 > + @param PhysicalAddressBits Physical address bits. >=20 > + @param RawMemoryRanges Return the randomly generated MTRRs. >=20 > + @param UcCount Count of Uncacheable MTRRs. >=20 > + @param WtCount Count of Write Through MTRRs. >=20 > + @param WbCount Count of Write Back MTRRs. >=20 > + @param WpCount Count of Write Protected MTRRs. >=20 > + @param WcCount Count of Write Combining MTRRs. >=20 > +**/ >=20 > +VOID >=20 > +GenerateValidAndConfigurableMtrrPairs ( >=20 > + IN UINT32 PhysicalAddressBits, >=20 > + IN OUT MTRR_MEMORY_RANGE *RawMemoryRanges, >=20 > + IN UINT32 UcCount, >=20 > + IN UINT32 WtCount, >=20 > + IN UINT32 WbCount, >=20 > + IN UINT32 WpCount, >=20 > + IN UINT32 WcCount >=20 > + ); >=20 > + >=20 > +/** >=20 > + Convert the MTRR BASE/MASK array to memory ranges. >=20 > + >=20 > + @param DefaultType Default memory type. >=20 > + @param PhysicalAddressBits Physical address bits. >=20 > + @param RawMemoryRanges Raw memory ranges. >=20 > + @param RawMemoryRangeCount Count of raw memory ranges. >=20 > + @param MemoryRanges Memory ranges. >=20 > + @param MemoryRangeCount Count of memory ranges. >=20 > +**/ >=20 > +VOID >=20 > +GetEffectiveMemoryRanges ( >=20 > + IN MTRR_MEMORY_CACHE_TYPE DefaultType, >=20 > + IN UINT32 PhysicalAddressBits, >=20 > + IN MTRR_MEMORY_RANGE *RawMemoryRanges, >=20 > + IN UINT32 RawMemoryRangeCount, >=20 > + OUT MTRR_MEMORY_RANGE *MemoryRanges, >=20 > + OUT UINTN *MemoryRangeCount >=20 > + ); >=20 > + >=20 > +/** >=20 > + Generate random MTRR BASE/MASK for a specified type. >=20 > + >=20 > + @param PhysicalAddressBits Physical address bits. >=20 > + @param CacheType Cache type. >=20 > + @param MtrrPair Return the random MTRR. >=20 > + @param MtrrMemoryRange Return the random memory range. >=20 > +**/ >=20 > +VOID >=20 > +GenerateRandomMtrrPair ( >=20 > + IN UINT32 PhysicalAddressBits, >=20 > + IN MTRR_MEMORY_CACHE_TYPE CacheType, >=20 > + OUT MTRR_VARIABLE_SETTING *MtrrPair, OPTIONAL >=20 > + OUT MTRR_MEMORY_RANGE *MtrrMemoryRange OPTIONAL >=20 > + ); >=20 > + >=20 > +/** >=20 > + Collect the test result. >=20 > + >=20 > + @param DefaultType Default memory type. >=20 > + @param PhysicalAddressBits Physical address bits. >=20 > + @param VariableMtrrCount Count of variable MTRRs. >=20 > + @param Mtrrs MTRR settings to collect from. >=20 > + @param Ranges Return the memory ranges. >=20 > + @param RangeCount Return the count of memory ranges. >=20 > + @param MtrrCount Return the count of variable MTRRs being u= sed. >=20 > +**/ >=20 > +VOID >=20 > +CollectTestResult ( >=20 > + IN MTRR_MEMORY_CACHE_TYPE DefaultType, >=20 > + IN UINT32 PhysicalAddressBits, >=20 > + IN UINT32 VariableMtrrCount, >=20 > + IN MTRR_SETTINGS *Mtrrs, >=20 > + OUT MTRR_MEMORY_RANGE *Ranges, >=20 > + IN OUT UINTN *RangeCount, >=20 > + OUT UINT32 *MtrrCount >=20 > + ); >=20 > + >=20 > +/** >=20 > + Return a 64bit random number. >=20 > + >=20 > + @param Start Start of the random number range. >=20 > + @param Limit Limit of the random number range. >=20 > + @return 64bit random number >=20 > +**/ >=20 > +UINT64 >=20 > +Random64 ( >=20 > + UINT64 Start, >=20 > + UINT64 Limit >=20 > + ); >=20 > + >=20 > +/** >=20 > + Return a 32bit random number. >=20 > + >=20 > + @param Start Start of the random number range. >=20 > + @param Limit Limit of the random number range. >=20 > + @return 32bit random number >=20 > +**/ >=20 > +UINT32 >=20 > +Random32 ( >=20 > + UINT32 Start, >=20 > + UINT32 Limit >=20 > + ); >=20 > +#endif >=20 > 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 >=20 > +# Unit tests of the MtrrLib instance of the MtrrLib class >=20 > +# >=20 > +# Copyright (c) 2020, Intel Corporation. All rights reserved.
>=20 > +# SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +## >=20 > + >=20 > +[Defines] >=20 > + INF_VERSION =3D 0x00010006 >=20 > + BASE_NAME =3D MtrrLibUnitTestHost >=20 > + FILE_GUID =3D A1542D84-B64D-4847-885E-0509084376A= B >=20 > + MODULE_TYPE =3D HOST_APPLICATION >=20 > + VERSION_STRING =3D 1.0 >=20 > + >=20 > +# >=20 > +# The following information is for reference only and not required by th= e build tools. >=20 > +# >=20 > +# VALID_ARCHITECTURES =3D IA32 X64 >=20 > +# >=20 > + >=20 > +[Sources] >=20 > + MtrrLibUnitTest.c >=20 > + MtrrLibUnitTest.h >=20 > + Support.c >=20 > + >=20 > +[Packages] >=20 > + MdePkg/MdePkg.dec >=20 > + UefiCpuPkg/UefiCpuPkg.dec >=20 > + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec >=20 > + >=20 > +[LibraryClasses] >=20 > + BaseLib >=20 > + BaseMemoryLib >=20 > + DebugLib >=20 > + MtrrLib >=20 > + UnitTestLib >=20 > + >=20 > +[Pcd] >=20 > + gUefiCpuPkgTokenSpaceGuid.PcdCpuNumberOfReservedVariableMtrrs ## SOM= ETIMES_CONSUMES >=20 > diff --git a/UefiCpuPkg/Library/MtrrLib/UnitTest/Support.c b/UefiCpuPkg/L= ibrary/MtrrLib/UnitTest/Support.c > new file mode 100644 > index 0000000000..9fe4b0278e > --- /dev/null > +++ b/UefiCpuPkg/Library/MtrrLib/UnitTest/Support.c > @@ -0,0 +1,913 @@ > +/** @file >=20 > + Unit tests of the MtrrLib instance of the MtrrLib class >=20 > + >=20 > + Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > + >=20 > +**/ >=20 > + >=20 > +#include "MtrrLibUnitTest.h" >=20 > + >=20 > +MTRR_MEMORY_CACHE_TYPE mMemoryCacheTypes[] =3D { >=20 > + CacheUncacheable, CacheWriteCombining, CacheWriteThrough, CacheWritePr= otected, CacheWriteBack >=20 > + }; >=20 > + >=20 > +UINT64 mFixedMtrrsValue[MTRR_NUMBER_OF_FIXED_M= TRR]; >=20 > +MSR_IA32_MTRR_PHYSBASE_REGISTER mVariableMtrrsPhysBase[MTRR_NUMBER_OF_V= ARIABLE_MTRR]; >=20 > +MSR_IA32_MTRR_PHYSMASK_REGISTER mVariableMtrrsPhysMask[MTRR_NUMBER_OF_V= ARIABLE_MTRR]; >=20 > +MSR_IA32_MTRR_DEF_TYPE_REGISTER mDefTypeMsr; >=20 > +MSR_IA32_MTRRCAP_REGISTER mMtrrCapMsr; >=20 > +CPUID_VERSION_INFO_EDX mCpuidVersionInfoEdx; >=20 > +CPUID_VIR_PHY_ADDRESS_SIZE_EAX mCpuidVirPhyAddressSizeEax; >=20 > + >=20 > +/** >=20 > + Retrieves CPUID information. >=20 > + >=20 > + Executes the CPUID instruction with EAX set to the value specified by = Index. >=20 > + This function always returns Index. >=20 > + If Eax is not NULL, then the value of EAX after CPUID is returned in E= ax. >=20 > + If Ebx is not NULL, then the value of EBX after CPUID is returned in E= bx. >=20 > + If Ecx is not NULL, then the value of ECX after CPUID is returned in E= cx. >=20 > + If Edx is not NULL, then the value of EDX after CPUID is returned in E= dx. >=20 > + This function is only available on IA-32 and x64. >=20 > + >=20 > + @param Index The 32-bit value to load into EAX prior to invoking the = CPUID >=20 > + instruction. >=20 > + @param Eax The pointer to the 32-bit EAX value returned by the CPUI= D >=20 > + instruction. This is an optional parameter that may be N= ULL. >=20 > + @param Ebx The pointer to the 32-bit EBX value returned by the CPUI= D >=20 > + instruction. This is an optional parameter that may be N= ULL. >=20 > + @param Ecx The pointer to the 32-bit ECX value returned by the CPUI= D >=20 > + instruction. This is an optional parameter that may be N= ULL. >=20 > + @param Edx The pointer to the 32-bit EDX value returned by the CPUI= D >=20 > + instruction. This is an optional parameter that may be N= ULL. >=20 > + >=20 > + @return Index. >=20 > + >=20 > +**/ >=20 > +UINT32 >=20 > +EFIAPI >=20 > +UnitTestMtrrLibAsmCpuid ( >=20 > + IN UINT32 Index, >=20 > + OUT UINT32 *Eax, OPTIONAL >=20 > + OUT UINT32 *Ebx, OPTIONAL >=20 > + OUT UINT32 *Ecx, OPTIONAL >=20 > + OUT UINT32 *Edx OPTIONAL >=20 > + ) >=20 > +{ >=20 > + switch (Index) { >=20 > + case CPUID_VERSION_INFO: >=20 > + if (Edx !=3D NULL) { >=20 > + *Edx =3D mCpuidVersionInfoEdx.Uint32; >=20 > + } >=20 > + return Index; >=20 > + break; >=20 > + case CPUID_EXTENDED_FUNCTION: >=20 > + if (Eax !=3D NULL) { >=20 > + *Eax =3D CPUID_VIR_PHY_ADDRESS_SIZE; >=20 > + } >=20 > + return Index; >=20 > + break; >=20 > + case CPUID_VIR_PHY_ADDRESS_SIZE: >=20 > + if (Eax !=3D NULL) { >=20 > + *Eax =3D mCpuidVirPhyAddressSizeEax.Uint32; >=20 > + } >=20 > + return Index; >=20 > + break; >=20 > + } >=20 > + >=20 > + // >=20 > + // Should never fall through to here >=20 > + // >=20 > + ASSERT(FALSE); >=20 > + return Index; >=20 > +} >=20 > + >=20 > +/** >=20 > + Returns a 64-bit Machine Specific Register(MSR). >=20 > + >=20 > + Reads and returns the 64-bit MSR specified by Index. No parameter chec= king is >=20 > + performed on Index, and some Index values may cause CPU exceptions. Th= e >=20 > + caller must either guarantee that Index is valid, or the caller must s= et up >=20 > + exception handlers to catch the exceptions. This function is only avai= lable >=20 > + on IA-32 and x64. >=20 > + >=20 > + @param MsrIndex The 32-bit MSR index to read. >=20 > + >=20 > + @return The value of the MSR identified by MsrIndex. >=20 > + >=20 > +**/ >=20 > +UINT64 >=20 > +EFIAPI >=20 > +UnitTestMtrrLibAsmReadMsr64( >=20 > + IN UINT32 MsrIndex >=20 > + ) >=20 > +{ >=20 > + UINT32 Index; >=20 > + >=20 > + for (Index =3D 0; Index < ARRAY_SIZE (mFixedMtrrsValue); Index++) { >=20 > + if (MsrIndex =3D=3D mFixedMtrrsIndex[Index]) { >=20 > + return mFixedMtrrsValue[Index]; >=20 > + } >=20 > + } >=20 > + >=20 > + if ((MsrIndex >=3D MSR_IA32_MTRR_PHYSBASE0) && >=20 > + (MsrIndex <=3D MSR_IA32_MTRR_PHYSMASK0 + (MTRR_NUMBER_OF_VARIABLE_= MTRR << 1))) { >=20 > + if (MsrIndex % 2 =3D=3D 0) { >=20 > + Index =3D (MsrIndex - MSR_IA32_MTRR_PHYSBASE0) >> 1; >=20 > + return mVariableMtrrsPhysBase[Index].Uint64; >=20 > + } else { >=20 > + Index =3D (MsrIndex - MSR_IA32_MTRR_PHYSMASK0) >> 1; >=20 > + return mVariableMtrrsPhysMask[Index].Uint64; >=20 > + } >=20 > + } >=20 > + >=20 > + if (MsrIndex =3D=3D MSR_IA32_MTRR_DEF_TYPE) { >=20 > + return mDefTypeMsr.Uint64; >=20 > + } >=20 > + >=20 > + if (MsrIndex =3D=3D MSR_IA32_MTRRCAP) { >=20 > + return mMtrrCapMsr.Uint64; >=20 > + } >=20 > + >=20 > + // >=20 > + // Should never fall through to here >=20 > + // >=20 > + ASSERT(FALSE); >=20 > + return 0; >=20 > +} >=20 > + >=20 > +/** >=20 > + Writes a 64-bit value to a Machine Specific Register(MSR), and returns= the >=20 > + value. >=20 > + >=20 > + Writes the 64-bit value specified by Value to the MSR specified by Ind= ex. The >=20 > + 64-bit value written to the MSR is returned. No parameter checking is >=20 > + performed on Index or Value, and some of these may cause CPU exception= s. The >=20 > + caller must either guarantee that Index and Value are valid, or the ca= ller >=20 > + must establish proper exception handlers. This function is only availa= ble on >=20 > + IA-32 and x64. >=20 > + >=20 > + @param MsrIndex The 32-bit MSR index to write. >=20 > + @param Value The 64-bit value to write to the MSR. >=20 > + >=20 > + @return Value >=20 > + >=20 > +**/ >=20 > +UINT64 >=20 > +EFIAPI >=20 > +UnitTestMtrrLibAsmWriteMsr64( >=20 > + IN UINT32 MsrIndex, >=20 > + IN UINT64 Value >=20 > + ) >=20 > +{ >=20 > + UINT32 Index; >=20 > + >=20 > + for (Index =3D 0; Index < ARRAY_SIZE (mFixedMtrrsValue); Index++) { >=20 > + if (MsrIndex =3D=3D mFixedMtrrsIndex[Index]) { >=20 > + mFixedMtrrsValue[Index] =3D Value; >=20 > + return Value; >=20 > + } >=20 > + } >=20 > + >=20 > + if ((MsrIndex >=3D MSR_IA32_MTRR_PHYSBASE0) && >=20 > + (MsrIndex <=3D MSR_IA32_MTRR_PHYSMASK0 + (MTRR_NUMBER_OF_VARIABLE_= MTRR << 1))) { >=20 > + if (MsrIndex % 2 =3D=3D 0) { >=20 > + Index =3D (MsrIndex - MSR_IA32_MTRR_PHYSBASE0) >> 1; >=20 > + mVariableMtrrsPhysBase[Index].Uint64 =3D Value; >=20 > + return Value; >=20 > + } else { >=20 > + Index =3D (MsrIndex - MSR_IA32_MTRR_PHYSMASK0) >> 1; >=20 > + mVariableMtrrsPhysMask[Index].Uint64 =3D Value; >=20 > + return Value; >=20 > + } >=20 > + } >=20 > + >=20 > + if (MsrIndex =3D=3D MSR_IA32_MTRR_DEF_TYPE) { >=20 > + mDefTypeMsr.Uint64 =3D Value; >=20 > + return Value; >=20 > + } >=20 > + >=20 > + if (MsrIndex =3D=3D MSR_IA32_MTRRCAP) { >=20 > + mMtrrCapMsr.Uint64 =3D Value; >=20 > + return Value; >=20 > + } >=20 > + >=20 > + // >=20 > + // Should never fall through to here >=20 > + // >=20 > + ASSERT(FALSE); >=20 > + return 0; >=20 > +} >=20 > + >=20 > +/** >=20 > + Initialize MTRR registers. >=20 > +**/ >=20 > + >=20 > +/** >=20 > + Initialize the MTRR registers. >=20 > + >=20 > + @param SystemParameter System parameter that controls the MTRR registe= rs initialization. >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +InitializeMtrrRegs ( >=20 > + IN MTRR_LIB_SYSTEM_PARAMETER *SystemParameter >=20 > + ) >=20 > +{ >=20 > + UINT32 Index; >=20 > + >=20 > + SetMem (mFixedMtrrsValue, sizeof (mFixedMtrrsValue), SystemParameter->= DefaultCacheType); >=20 > + >=20 > + for (Index =3D 0; Index < ARRAY_SIZE (mVariableMtrrsPhysBase); Index++= ) { >=20 > + mVariableMtrrsPhysBase[Index].Uint64 =3D 0; >=20 > + mVariableMtrrsPhysBase[Index].Bits.Type =3D SystemParameter->De= faultCacheType; >=20 > + mVariableMtrrsPhysBase[Index].Bits.Reserved1 =3D 0; >=20 > + >=20 > + mVariableMtrrsPhysMask[Index].Uint64 =3D 0; >=20 > + mVariableMtrrsPhysMask[Index].Bits.V =3D 0; >=20 > + mVariableMtrrsPhysMask[Index].Bits.Reserved1 =3D 0; >=20 > + } >=20 > + >=20 > + mDefTypeMsr.Bits.E =3D 1; >=20 > + mDefTypeMsr.Bits.FE =3D 1; >=20 > + mDefTypeMsr.Bits.Type =3D SystemParameter->DefaultCacheType; >=20 > + mDefTypeMsr.Bits.Reserved1 =3D 0; >=20 > + mDefTypeMsr.Bits.Reserved2 =3D 0; >=20 > + mDefTypeMsr.Bits.Reserved3 =3D 0; >=20 > + >=20 > + mMtrrCapMsr.Bits.SMRR =3D 0; >=20 > + mMtrrCapMsr.Bits.WC =3D 0; >=20 > + mMtrrCapMsr.Bits.VCNT =3D SystemParameter->VariableMtrrCount; >=20 > + mMtrrCapMsr.Bits.FIX =3D SystemParameter->FixedMtrrSupported; >=20 > + mMtrrCapMsr.Bits.Reserved1 =3D 0; >=20 > + mMtrrCapMsr.Bits.Reserved2 =3D 0; >=20 > + mMtrrCapMsr.Bits.Reserved3 =3D 0; >=20 > + >=20 > + mCpuidVersionInfoEdx.Bits.MTRR =3D SystemParamete= r->MtrrSupported; >=20 > + mCpuidVirPhyAddressSizeEax.Bits.PhysicalAddressBits =3D SystemParamete= r->PhysicalAddressBits; >=20 > + >=20 > + // >=20 > + // Hook BaseLib functions used by MtrrLib that require some emulation. >=20 > + // >=20 > + gUnitTestHostBaseLib.X86->AsmCpuid =3D UnitTestMtrrLibAsmCpuid; >=20 > + gUnitTestHostBaseLib.X86->AsmReadMsr64 =3D UnitTestMtrrLibAsmReadMsr6= 4; >=20 > + gUnitTestHostBaseLib.X86->AsmWriteMsr64 =3D UnitTestMtrrLibAsmWriteMsr= 64; >=20 > + >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Collect the test result. >=20 > + >=20 > + @param DefaultType Default memory type. >=20 > + @param PhysicalAddressBits Physical address bits. >=20 > + @param VariableMtrrCount Count of variable MTRRs. >=20 > + @param Mtrrs MTRR settings to collect from. >=20 > + @param Ranges Return the memory ranges. >=20 > + @param RangeCount Return the count of memory ranges. >=20 > + @param MtrrCount Return the count of variable MTRRs being u= sed. >=20 > +**/ >=20 > +VOID >=20 > +CollectTestResult ( >=20 > + IN MTRR_MEMORY_CACHE_TYPE DefaultType, >=20 > + IN UINT32 PhysicalAddressBits, >=20 > + IN UINT32 VariableMtrrCount, >=20 > + IN MTRR_SETTINGS *Mtrrs, >=20 > + OUT MTRR_MEMORY_RANGE *Ranges, >=20 > + IN OUT UINTN *RangeCount, >=20 > + OUT UINT32 *MtrrCount >=20 > + ) >=20 > +{ >=20 > + UINTN Index; >=20 > + UINT64 MtrrValidBitsMask; >=20 > + UINT64 MtrrValidAddressMask; >=20 > + MTRR_MEMORY_RANGE RawMemoryRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)]; >=20 > + >=20 > + ASSERT (Mtrrs !=3D NULL); >=20 > + ASSERT (VariableMtrrCount <=3D ARRAY_SIZE (Mtrrs->Variables.Mtrr)); >=20 > + >=20 > + MtrrValidBitsMask =3D (1ull << PhysicalAddressBits) - 1; >=20 > + MtrrValidAddressMask =3D MtrrValidBitsMask & ~0xFFFull; >=20 > + >=20 > + *MtrrCount =3D 0; >=20 > + for (Index =3D 0; Index < VariableMtrrCount; Index++) { >=20 > + if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &Mtrrs->Variables.Mtrr[Inde= x].Mask)->Bits.V =3D=3D 1) { >=20 > + RawMemoryRanges[*MtrrCount].BaseAddress =3D Mtrrs->Variables.Mtrr[= Index].Base & MtrrValidAddressMask; >=20 > + RawMemoryRanges[*MtrrCount].Type =3D >=20 > + ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &Mtrrs->Variables.Mtrr[Inde= x].Base)->Bits.Type; >=20 > + RawMemoryRanges[*MtrrCount].Length =3D >=20 > + ((~(Mtrrs->Variables.Mtrr[Index].Mask & MtrrValidAddressMask))= & MtrrValidBitsMask) + 1; >=20 > + (*MtrrCount)++; >=20 > + } >=20 > + } >=20 > + >=20 > + GetEffectiveMemoryRanges (DefaultType, PhysicalAddressBits, RawMemoryR= anges, *MtrrCount, Ranges, RangeCount); >=20 > +} >=20 > + >=20 > +/** >=20 > + Return a 32bit random number. >=20 > + >=20 > + @param Start Start of the random number range. >=20 > + @param Limit Limit of the random number range. >=20 > + @return 32bit random number >=20 > +**/ >=20 > +UINT32 >=20 > +Random32 ( >=20 > + UINT32 Start, >=20 > + UINT32 Limit >=20 > + ) >=20 > +{ >=20 > + return (UINT32) (((double) rand () / RAND_MAX) * (Limit - Start)) + St= art; >=20 > +} >=20 > + >=20 > +/** >=20 > + Return a 64bit random number. >=20 > + >=20 > + @param Start Start of the random number range. >=20 > + @param Limit Limit of the random number range. >=20 > + @return 64bit random number >=20 > +**/ >=20 > +UINT64 >=20 > +Random64 ( >=20 > + UINT64 Start, >=20 > + UINT64 Limit >=20 > + ) >=20 > +{ >=20 > + return (UINT64) (((double) rand () / RAND_MAX) * (Limit - Start)) + St= art; >=20 > +} >=20 > + >=20 > +/** >=20 > + Generate random MTRR BASE/MASK for a specified type. >=20 > + >=20 > + @param PhysicalAddressBits Physical address bits. >=20 > + @param CacheType Cache type. >=20 > + @param MtrrPair Return the random MTRR. >=20 > + @param MtrrMemoryRange Return the random memory range. >=20 > +**/ >=20 > +VOID >=20 > +GenerateRandomMtrrPair ( >=20 > + IN UINT32 PhysicalAddressBits, >=20 > + IN MTRR_MEMORY_CACHE_TYPE CacheType, >=20 > + OUT MTRR_VARIABLE_SETTING *MtrrPair, OPTIONAL >=20 > + OUT MTRR_MEMORY_RANGE *MtrrMemoryRange OPTIONAL >=20 > + ) >=20 > +{ >=20 > + MSR_IA32_MTRR_PHYSBASE_REGISTER PhysBase; >=20 > + MSR_IA32_MTRR_PHYSMASK_REGISTER PhysMask; >=20 > + UINT32 SizeShift; >=20 > + UINT32 BaseShift; >=20 > + UINT64 RandomBoundary; >=20 > + UINT64 MaxPhysicalAddress; >=20 > + UINT64 RangeSize; >=20 > + UINT64 RangeBase; >=20 > + UINT64 PhysBasePhyMaskValidBitsMask; >=20 > + >=20 > + MaxPhysicalAddress =3D 1ull << PhysicalAddressBits; >=20 > + do { >=20 > + SizeShift =3D Random32 (12, PhysicalAddressBits - 1); >=20 > + RangeSize =3D 1ull << SizeShift; >=20 > + >=20 > + BaseShift =3D Random32 (SizeShift, PhysicalAddressBits - 1); >=20 > + RandomBoundary =3D Random64 (0, 1ull << (PhysicalAddressBits - BaseS= hift)); >=20 > + RangeBase =3D RandomBoundary << BaseShift; >=20 > + } while (RangeBase < SIZE_1MB || RangeBase > MaxPhysicalAddress - 1); >=20 > + >=20 > + PhysBasePhyMaskValidBitsMask =3D (MaxPhysicalAddress - 1) & 0xffffffff= fffff000ULL; >=20 > + >=20 > + PhysBase.Uint64 =3D 0; >=20 > + PhysBase.Bits.Type =3D CacheType; >=20 > + PhysBase.Uint64 |=3D RangeBase & PhysBasePhyMaskValidBitsMask; >=20 > + PhysMask.Uint64 =3D 0; >=20 > + PhysMask.Bits.V =3D 1; >=20 > + PhysMask.Uint64 |=3D ((~RangeSize) + 1) & PhysBasePhyMaskValidBitsMa= sk; >=20 > + >=20 > + if (MtrrPair !=3D NULL) { >=20 > + MtrrPair->Base =3D PhysBase.Uint64; >=20 > + MtrrPair->Mask =3D PhysMask.Uint64; >=20 > + } >=20 > + >=20 > + if (MtrrMemoryRange !=3D NULL) { >=20 > + MtrrMemoryRange->BaseAddress =3D RangeBase; >=20 > + MtrrMemoryRange->Length =3D RangeSize; >=20 > + MtrrMemoryRange->Type =3D CacheType; >=20 > + } >=20 > +} >=20 > + >=20 > + >=20 > +/** >=20 > + Check whether the Range overlaps with any one in Ranges. >=20 > + >=20 > + @param Range The memory range to check. >=20 > + @param Ranges The memory ranges. >=20 > + @param Count Count of memory ranges. >=20 > + >=20 > + @return TRUE when overlap exists. >=20 > +**/ >=20 > +BOOLEAN >=20 > +RangesOverlap ( >=20 > + IN MTRR_MEMORY_RANGE *Range, >=20 > + IN MTRR_MEMORY_RANGE *Ranges, >=20 > + IN UINTN Count >=20 > + ) >=20 > +{ >=20 > + while (Count-- !=3D 0) { >=20 > + // >=20 > + // Two ranges overlap when: >=20 > + // 1. range#2.base is in the middle of range#1 >=20 > + // 2. range#1.base is in the middle of range#2 >=20 > + // >=20 > + if ((Range->BaseAddress <=3D Ranges[Count].BaseAddress && Ranges[Cou= nt].BaseAddress < Range->BaseAddress + > Range->Length) >=20 > + || (Ranges[Count].BaseAddress <=3D Range->BaseAddress && Range->Bas= eAddress < Ranges[Count].BaseAddress + > Ranges[Count].Length)) { >=20 > + return TRUE; >=20 > + } >=20 > + } >=20 > + return FALSE; >=20 > +} >=20 > + >=20 > +/** >=20 > + Generate random MTRRs. >=20 > + >=20 > + @param PhysicalAddressBits Physical address bits. >=20 > + @param RawMemoryRanges Return the randomly generated MTRRs. >=20 > + @param UcCount Count of Uncacheable MTRRs. >=20 > + @param WtCount Count of Write Through MTRRs. >=20 > + @param WbCount Count of Write Back MTRRs. >=20 > + @param WpCount Count of Write Protected MTRRs. >=20 > + @param WcCount Count of Write Combine MTRRs. >=20 > +**/ >=20 > +VOID >=20 > +GenerateValidAndConfigurableMtrrPairs ( >=20 > + IN UINT32 PhysicalAddressBits, >=20 > + IN OUT MTRR_MEMORY_RANGE *RawMemoryRanges, >=20 > + IN UINT32 UcCount, >=20 > + IN UINT32 WtCount, >=20 > + IN UINT32 WbCount, >=20 > + IN UINT32 WpCount, >=20 > + IN UINT32 WcCount >=20 > + ) >=20 > +{ >=20 > + UINT32 Index; >=20 > + >=20 > + // >=20 > + // 1. Generate UC, WT, WB in order. >=20 > + // >=20 > + for (Index =3D 0; Index < UcCount; Index++) { >=20 > + GenerateRandomMtrrPair (PhysicalAddressBits, CacheUncacheable, NULL,= &RawMemoryRanges[Index]); >=20 > + } >=20 > + >=20 > + for (Index =3D UcCount; Index < UcCount + WtCount; Index++) { >=20 > + GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteThrough, NULL= , &RawMemoryRanges[Index]); >=20 > + } >=20 > + >=20 > + for (Index =3D UcCount + WtCount; Index < UcCount + WtCount + WbCount;= Index++) { >=20 > + GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteBack, NULL, &= RawMemoryRanges[Index]); >=20 > + } >=20 > + >=20 > + // >=20 > + // 2. Generate WP MTRR and DO NOT overlap with WT, WB. >=20 > + // >=20 > + for (Index =3D UcCount + WtCount + WbCount; Index < UcCount + WtCount = + WbCount + WpCount; Index++) { >=20 > + GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteProtected, NU= LL, &RawMemoryRanges[Index]); >=20 > + while (RangesOverlap (&RawMemoryRanges[Index], &RawMemoryRanges[UcCo= unt], WtCount + WbCount)) { >=20 > + GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteProtected, = NULL, &RawMemoryRanges[Index]); >=20 > + } >=20 > + } >=20 > + >=20 > + // >=20 > + // 3. Generate WC MTRR and DO NOT overlap with WT, WB, WP. >=20 > + // >=20 > + for (Index =3D UcCount + WtCount + WbCount + WpCount; Index < UcCount = + WtCount + WbCount + WpCount + WcCount; > Index++) { >=20 > + GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteCombining, NU= LL, &RawMemoryRanges[Index]); >=20 > + while (RangesOverlap (&RawMemoryRanges[Index], &RawMemoryRanges[UcCo= unt], WtCount + WbCount + WpCount)) > { >=20 > + GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteCombining, = NULL, &RawMemoryRanges[Index]); >=20 > + } >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Return a random memory cache type. >=20 > +**/ >=20 > +MTRR_MEMORY_CACHE_TYPE >=20 > +GenerateRandomCacheType ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + return mMemoryCacheTypes[Random32 (0, ARRAY_SIZE (mMemoryCacheTypes)= - 1)]; >=20 > +} >=20 > + >=20 > +/** >=20 > + Compare function used by qsort(). >=20 > +**/ >=20 > + >=20 > +/** >=20 > + Compare function used by qsort(). >=20 > + >=20 > + @param Left Left operand to compare. >=20 > + @param Right Right operand to compare. >=20 > + >=20 > + @retval 0 Left =3D=3D Right >=20 > + @retval -1 Left < Right >=20 > + @retval 1 Left > Right >=20 > +**/ >=20 > +INT32 >=20 > +CompareFuncUint64 ( >=20 > + CONST VOID * Left, >=20 > + CONST VOID * Right >=20 > + ) >=20 > +{ >=20 > + INT64 Delta; >=20 > + Delta =3D (*(UINT64*)Left - *(UINT64*)Right); >=20 > + if (Delta > 0) { >=20 > + return 1; >=20 > + } else if (Delta =3D=3D 0) { >=20 > + return 0; >=20 > + } else { >=20 > + return -1; >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Determin the memory cache type for the Range. >=20 > + >=20 > + @param DefaultType Default cache type. >=20 > + @param Range The memory range to determin the cache type. >=20 > + @param Ranges The entire memory ranges. >=20 > + @param RangeCount Count of the entire memory ranges. >=20 > +**/ >=20 > +VOID >=20 > +DetermineMemoryCacheType ( >=20 > + IN MTRR_MEMORY_CACHE_TYPE DefaultType, >=20 > + IN OUT MTRR_MEMORY_RANGE *Range, >=20 > + IN MTRR_MEMORY_RANGE *Ranges, >=20 > + IN UINT32 RangeCount >=20 > + ) >=20 > +{ >=20 > + UINT32 Index; >=20 > + Range->Type =3D CacheInvalid; >=20 > + for (Index =3D 0; Index < RangeCount; Index++) { >=20 > + if (RangesOverlap (Range, &Ranges[Index], 1)) { >=20 > + if (Ranges[Index].Type < Range->Type) { >=20 > + Range->Type =3D Ranges[Index].Type; >=20 > + } >=20 > + } >=20 > + } >=20 > + >=20 > + if (Range->Type =3D=3D CacheInvalid) { >=20 > + Range->Type =3D DefaultType; >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Get the index of the element that does NOT equals to Array[Index]. >=20 > + >=20 > + @param Index Current element. >=20 > + @param Array Array to scan. >=20 > + @param Count Count of the array. >=20 > + >=20 > + @return Next element that doesn't equal to current one. >=20 > +**/ >=20 > +UINT32 >=20 > +GetNextDifferentElementInSortedArray ( >=20 > + IN UINT32 Index, >=20 > + IN UINT64 *Array, >=20 > + IN UINT32 Count >=20 > + ) >=20 > +{ >=20 > + UINT64 CurrentElement; >=20 > + CurrentElement =3D Array[Index]; >=20 > + while (CurrentElement =3D=3D Array[Index] && Index < Count) { >=20 > + Index++; >=20 > + } >=20 > + return Index; >=20 > +} >=20 > + >=20 > +/** >=20 > + Remove the duplicates from the array. >=20 > + >=20 > + @param Array The array to operate on. >=20 > + @param Count Count of the array. >=20 > +**/ >=20 > +VOID >=20 > +RemoveDuplicatesInSortedArray ( >=20 > + IN OUT UINT64 *Array, >=20 > + IN OUT UINT32 *Count >=20 > + ) >=20 > +{ >=20 > + UINT32 Index; >=20 > + UINT32 NewCount; >=20 > + >=20 > + Index =3D 0; >=20 > + NewCount =3D 0; >=20 > + while (Index < *Count) { >=20 > + Array[NewCount] =3D Array[Index]; >=20 > + NewCount++; >=20 > + Index =3D GetNextDifferentElementInSortedArray (Index, Array, *Count= ); >=20 > + } >=20 > + *Count =3D NewCount; >=20 > +} >=20 > + >=20 > +/** >=20 > + Return TRUE when Address is in the Range. >=20 > + >=20 > + @param Address The address to check. >=20 > + @param Range The range to check. >=20 > + @return TRUE when Address is in the Range. >=20 > +**/ >=20 > +BOOLEAN >=20 > +AddressInRange ( >=20 > + IN UINT64 Address, >=20 > + IN MTRR_MEMORY_RANGE Range >=20 > + ) >=20 > +{ >=20 > + return (Address >=3D Range.BaseAddress) && (Address <=3D Range.BaseA= ddress + Range.Length - 1); >=20 > +} >=20 > + >=20 > +/** >=20 > + Get the overlap bit flag. >=20 > + >=20 > + @param RawMemoryRanges Raw memory ranges. >=20 > + @param RawMemoryRangeCount Count of raw memory ranges. >=20 > + @param Address The address to check. >=20 > +**/ >=20 > +UINT64 >=20 > +GetOverlapBitFlag ( >=20 > + IN MTRR_MEMORY_RANGE *RawMemoryRanges, >=20 > + IN UINT32 RawMemoryRangeCount, >=20 > + IN UINT64 Address >=20 > + ) >=20 > +{ >=20 > + UINT64 OverlapBitFlag; >=20 > + UINT32 Index; >=20 > + OverlapBitFlag =3D 0; >=20 > + for (Index =3D 0; Index < RawMemoryRangeCount; Index++) { >=20 > + if (AddressInRange (Address, RawMemoryRanges[Index])) { >=20 > + OverlapBitFlag |=3D (1ull << Index); >=20 > + } >=20 > + } >=20 > + >=20 > + return OverlapBitFlag; >=20 > +} >=20 > + >=20 > +/** >=20 > + Return the relationship between flags. >=20 > + >=20 > + @param Flag1 Flag 1 >=20 > + @param Flag2 Flag 2 >=20 > + >=20 > + @retval 0 Flag1 =3D=3D Flag2 >=20 > + @retval 1 Flag1 is a subset of Flag2 >=20 > + @retval 2 Flag2 is a subset of Flag1 >=20 > + @retval 3 No subset relations between Flag1 and Flag2. >=20 > +**/ >=20 > +UINT32 >=20 > +CheckOverlapBitFlagsRelation ( >=20 > + IN UINT64 Flag1, >=20 > + IN UINT64 Flag2 >=20 > + ) >=20 > +{ >=20 > + if (Flag1 =3D=3D Flag2) return 0; >=20 > + if ((Flag1 | Flag2) =3D=3D Flag2) return 1; >=20 > + if ((Flag1 | Flag2) =3D=3D Flag1) return 2; >=20 > + return 3; >=20 > +} >=20 > + >=20 > +/** >=20 > + Return TRUE when the Endpoint is in any of the Ranges. >=20 > + >=20 > + @param Endpoint The endpoint to check. >=20 > + @param Ranges The memory ranges. >=20 > + @param RangeCount Count of memory ranges. >=20 > + >=20 > + @retval TRUE Endpoint is in one of the range. >=20 > + @retval FALSE Endpoint is not in any of the ranges. >=20 > +**/ >=20 > +BOOLEAN >=20 > +IsEndpointInRanges ( >=20 > + IN UINT64 Endpoint, >=20 > + IN MTRR_MEMORY_RANGE *Ranges, >=20 > + IN UINTN RangeCount >=20 > + ) >=20 > +{ >=20 > + UINT32 Index; >=20 > + for (Index =3D 0; Index < RangeCount; Index++) { >=20 > + if (AddressInRange (Endpoint, Ranges[Index])) { >=20 > + return TRUE; >=20 > + } >=20 > + } >=20 > + return FALSE; >=20 > +} >=20 > + >=20 > + >=20 > +/** >=20 > + Compact adjacent ranges of the same type. >=20 > + >=20 > + @param DefaultType Default memory type. >=20 > + @param PhysicalAddressBits Physical address bits. >=20 > + @param EffectiveMtrrMemoryRanges Memory ranges to compact. >=20 > + @param EffectiveMtrrMemoryRangesCount Return the new count of memory r= anges. >=20 > +**/ >=20 > +VOID >=20 > +CompactAndExtendEffectiveMtrrMemoryRanges ( >=20 > + IN MTRR_MEMORY_CACHE_TYPE DefaultType, >=20 > + IN UINT32 PhysicalAddressBits, >=20 > + IN OUT MTRR_MEMORY_RANGE **EffectiveMtrrMemoryRanges, >=20 > + IN OUT UINTN *EffectiveMtrrMemoryRangesCount >=20 > + ) >=20 > +{ >=20 > + UINT64 MaxAddress; >=20 > + UINTN NewRangesCountAtMost; >=20 > + MTRR_MEMORY_RANGE *NewRanges; >=20 > + UINTN NewRangesCountActual; >=20 > + MTRR_MEMORY_RANGE *CurrentRangeInNewRanges; >=20 > + MTRR_MEMORY_CACHE_TYPE CurrentRangeTypeInOldRanges; >=20 > + >=20 > + MTRR_MEMORY_RANGE *OldRanges; >=20 > + MTRR_MEMORY_RANGE OldLastRange; >=20 > + UINTN OldRangesIndex; >=20 > + >=20 > + NewRangesCountActual =3D 0; >=20 > + NewRangesCountAtMost =3D *EffectiveMtrrMemoryRangesCount + 2; // At = most with 2 more range entries. >=20 > + NewRanges =3D (MTRR_MEMORY_RANGE *) calloc (NewRangesCountA= tMost, sizeof (MTRR_MEMORY_RANGE)); >=20 > + OldRanges =3D *EffectiveMtrrMemoryRanges; >=20 > + if (OldRanges[0].BaseAddress > 0) { >=20 > + NewRanges[NewRangesCountActual].BaseAddress =3D 0; >=20 > + NewRanges[NewRangesCountActual].Length =3D OldRanges[0].BaseAdd= ress; >=20 > + NewRanges[NewRangesCountActual].Type =3D DefaultType; >=20 > + NewRangesCountActual++; >=20 > + } >=20 > + >=20 > + OldRangesIndex =3D 0; >=20 > + while (OldRangesIndex < *EffectiveMtrrMemoryRangesCount) { >=20 > + CurrentRangeTypeInOldRanges =3D OldRanges[OldRangesIndex].Type; >=20 > + CurrentRangeInNewRanges =3D NULL; >=20 > + if (NewRangesCountActual > 0) // We need to check CurrentNewRange = first before generate a new NewRange. >=20 > + { >=20 > + CurrentRangeInNewRanges =3D &NewRanges[NewRangesCountActual - 1]; >=20 > + } >=20 > + if (CurrentRangeInNewRanges !=3D NULL && CurrentRangeInNewRanges->Ty= pe =3D=3D CurrentRangeTypeInOldRanges) { >=20 > + CurrentRangeInNewRanges->Length +=3D OldRanges[OldRangesIndex].Len= gth; >=20 > + } else { >=20 > + NewRanges[NewRangesCountActual].BaseAddress =3D OldRanges[OldRange= sIndex].BaseAddress; >=20 > + NewRanges[NewRangesCountActual].Length +=3D OldRanges[OldRange= sIndex].Length; >=20 > + NewRanges[NewRangesCountActual].Type =3D CurrentRangeTypeIn= OldRanges; >=20 > + while (OldRangesIndex + 1 < *EffectiveMtrrMemoryRangesCount && Old= Ranges[OldRangesIndex + 1].Type =3D=3D > CurrentRangeTypeInOldRanges) >=20 > + { >=20 > + OldRangesIndex++; >=20 > + NewRanges[NewRangesCountActual].Length +=3D OldRanges[OldRangesI= ndex].Length; >=20 > + } >=20 > + NewRangesCountActual++; >=20 > + } >=20 > + >=20 > + OldRangesIndex++; >=20 > + } >=20 > + >=20 > + MaxAddress =3D (1ull << PhysicalAddressBits) - 1; >=20 > + OldLastRange =3D OldRanges[(*EffectiveMtrrMemoryRangesCount) - 1]; >=20 > + CurrentRangeInNewRanges =3D &NewRanges[NewRangesCountActual - 1]; >=20 > + if (OldLastRange.BaseAddress + OldLastRange.Length - 1 < MaxAddress) { >=20 > + if (CurrentRangeInNewRanges->Type =3D=3D DefaultType) { >=20 > + CurrentRangeInNewRanges->Length =3D MaxAddress - CurrentRangeInNew= Ranges->BaseAddress + 1; >=20 > + } else { >=20 > + NewRanges[NewRangesCountActual].BaseAddress =3D OldLastRange.BaseA= ddress + OldLastRange.Length; >=20 > + NewRanges[NewRangesCountActual].Length =3D MaxAddress - NewRanges[= NewRangesCountActual].BaseAddress + 1; >=20 > + NewRanges[NewRangesCountActual].Type =3D DefaultType; >=20 > + NewRangesCountActual++; >=20 > + } >=20 > + } >=20 > + >=20 > + free (*EffectiveMtrrMemoryRanges); >=20 > + *EffectiveMtrrMemoryRanges =3D NewRanges; >=20 > + *EffectiveMtrrMemoryRangesCount =3D NewRangesCountActual; >=20 > +} >=20 > + >=20 > +/** >=20 > + Collect all the endpoints in the raw memory ranges. >=20 > + >=20 > + @param Endpoints Return the collected endpoints. >=20 > + @param EndPointCount Return the count of endpoints. >=20 > + @param RawMemoryRanges Raw memory ranges. >=20 > + @param RawMemoryRangeCount Count of raw memory ranges. >=20 > +**/ >=20 > +VOID >=20 > +CollectEndpoints ( >=20 > + IN OUT UINT64 *Endpoints, >=20 > + IN OUT UINT32 *EndPointCount, >=20 > + IN MTRR_MEMORY_RANGE *RawMemoryRanges, >=20 > + IN UINT32 RawMemoryRangeCount >=20 > + ) >=20 > +{ >=20 > + UINT32 Index; >=20 > + UINT32 RawRangeIndex; >=20 > + >=20 > + ASSERT ((RawMemoryRangeCount << 1) =3D=3D *EndPointCount); >=20 > + >=20 > + for (Index =3D 0; Index < *EndPointCount; Index +=3D 2) { >=20 > + RawRangeIndex =3D Index >> 1; >=20 > + Endpoints[Index] =3D RawMemoryRanges[RawRangeIndex].BaseAddress; >=20 > + Endpoints[Index + 1] =3D RawMemoryRanges[RawRangeIndex].BaseAddress = + RawMemoryRanges[RawRangeIndex].Length > - 1; >=20 > + } >=20 > + >=20 > + qsort (Endpoints, *EndPointCount, sizeof (UINT64), CompareFuncUint64); >=20 > + RemoveDuplicatesInSortedArray (Endpoints, EndPointCount); >=20 > +} >=20 > + >=20 > +/** >=20 > + Convert the MTRR BASE/MASK array to memory ranges. >=20 > + >=20 > + @param DefaultType Default memory type. >=20 > + @param PhysicalAddressBits Physical address bits. >=20 > + @param RawMemoryRanges Raw memory ranges. >=20 > + @param RawMemoryRangeCount Count of raw memory ranges. >=20 > + @param MemoryRanges Memory ranges. >=20 > + @param MemoryRangeCount Count of memory ranges. >=20 > +**/ >=20 > +VOID >=20 > +GetEffectiveMemoryRanges ( >=20 > + IN MTRR_MEMORY_CACHE_TYPE DefaultType, >=20 > + IN UINT32 PhysicalAddressBits, >=20 > + IN MTRR_MEMORY_RANGE *RawMemoryRanges, >=20 > + IN UINT32 RawMemoryRangeCount, >=20 > + OUT MTRR_MEMORY_RANGE *MemoryRanges, >=20 > + OUT UINTN *MemoryRangeCount >=20 > + ) >=20 > +{ >=20 > + UINTN Index; >=20 > + UINT32 AllEndPointsCount; >=20 > + UINT64 *AllEndPointsInclusive; >=20 > + UINT32 AllRangePiecesCountMax; >=20 > + MTRR_MEMORY_RANGE *AllRangePieces; >=20 > + UINTN AllRangePiecesCountActual; >=20 > + UINT64 OverlapBitFlag1; >=20 > + UINT64 OverlapBitFlag2; >=20 > + INT32 OverlapFlagRelation; >=20 > + >=20 > + if (RawMemoryRangeCount =3D=3D 0) { >=20 > + MemoryRanges[0].BaseAddress =3D 0; >=20 > + MemoryRanges[0].Length =3D (1ull << PhysicalAddressBits); >=20 > + MemoryRanges[0].Type =3D DefaultType; >=20 > + *MemoryRangeCount =3D 1; >=20 > + return; >=20 > + } >=20 > + >=20 > + AllEndPointsCount =3D RawMemoryRangeCount << 1; >=20 > + AllEndPointsInclusive =3D calloc (AllEndPointsCount, sizeof (UINT6= 4)); >=20 > + AllRangePiecesCountMax =3D RawMemoryRangeCount * 3 + 1; >=20 > + AllRangePieces =3D calloc (AllRangePiecesCountMax, sizeof (= MTRR_MEMORY_RANGE)); >=20 > + CollectEndpoints (AllEndPointsInclusive, &AllEndPointsCount, RawMemory= Ranges, RawMemoryRangeCount); >=20 > + >=20 > + for (Index =3D 0, AllRangePiecesCountActual =3D 0; Index < AllEndPoint= sCount - 1; Index++) { >=20 > + OverlapBitFlag1 =3D GetOverlapBitFlag (RawMemoryRanges, RawMemoryRan= geCount, AllEndPointsInclusive[Index]); >=20 > + OverlapBitFlag2 =3D GetOverlapBitFlag (RawMemoryRanges, RawMemoryRan= geCount, AllEndPointsInclusive[Index + 1]); >=20 > + OverlapFlagRelation =3D CheckOverlapBitFlagsRelation (OverlapBitFlag= 1, OverlapBitFlag2); >=20 > + switch (OverlapFlagRelation) { >=20 > + case 0: // [1, 2] >=20 > + AllRangePieces[AllRangePiecesCountActual].BaseAddress =3D AllEnd= PointsInclusive[Index]; >=20 > + AllRangePieces[AllRangePiecesCountActual].Length =3D AllEnd= PointsInclusive[Index + 1] - > AllEndPointsInclusive[Index] + 1; >=20 > + AllRangePiecesCountActual++; >=20 > + break; >=20 > + case 1: // [1, 2) >=20 > + AllRangePieces[AllRangePiecesCountActual].BaseAddress =3D AllEnd= PointsInclusive[Index]; >=20 > + AllRangePieces[AllRangePiecesCountActual].Length =3D (AllEn= dPointsInclusive[Index + 1] - 1) - > AllEndPointsInclusive[Index] + 1; >=20 > + AllRangePiecesCountActual++; >=20 > + break; >=20 > + case 2: // (1, 2] >=20 > + AllRangePieces[AllRangePiecesCountActual].BaseAddress =3D AllEnd= PointsInclusive[Index] + 1; >=20 > + AllRangePieces[AllRangePiecesCountActual].Length =3D AllEnd= PointsInclusive[Index + 1] - > (AllEndPointsInclusive[Index] + 1) + 1; >=20 > + AllRangePiecesCountActual++; >=20 > + >=20 > + if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRangeP= ieces, AllRangePiecesCountActual)) { >=20 > + AllRangePieces[AllRangePiecesCountActual].BaseAddress =3D AllE= ndPointsInclusive[Index]; >=20 > + AllRangePieces[AllRangePiecesCountActual].Length =3D 1; >=20 > + AllRangePiecesCountActual++; >=20 > + } >=20 > + break; >=20 > + case 3: // (1, 2) >=20 > + AllRangePieces[AllRangePiecesCountActual].BaseAddress =3D AllEnd= PointsInclusive[Index] + 1; >=20 > + AllRangePieces[AllRangePiecesCountActual].Length =3D (AllEn= dPointsInclusive[Index + 1] - 1) - > (AllEndPointsInclusive[Index] + 1) + 1; >=20 > + if (AllRangePieces[AllRangePiecesCountActual].Length =3D=3D 0) = // Only in case 3 can exists Length=3D0, we should skip > such "segment". >=20 > + break; >=20 > + AllRangePiecesCountActual++; >=20 > + if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRangeP= ieces, AllRangePiecesCountActual)) { >=20 > + AllRangePieces[AllRangePiecesCountActual].BaseAddress =3D AllE= ndPointsInclusive[Index]; >=20 > + AllRangePieces[AllRangePiecesCountActual].Length =3D 1; >=20 > + AllRangePiecesCountActual++; >=20 > + } >=20 > + break; >=20 > + default: >=20 > + ASSERT (FALSE); >=20 > + } >=20 > + } >=20 > + >=20 > + for (Index =3D 0; Index < AllRangePiecesCountActual; Index++) { >=20 > + DetermineMemoryCacheType (DefaultType, &AllRangePieces[Index], RawMe= moryRanges, RawMemoryRangeCount); >=20 > + } >=20 > + >=20 > + CompactAndExtendEffectiveMtrrMemoryRanges (DefaultType, PhysicalAddres= sBits, &AllRangePieces, > &AllRangePiecesCountActual); >=20 > + ASSERT (*MemoryRangeCount >=3D AllRangePiecesCountActual); >=20 > + memcpy (MemoryRanges, AllRangePieces, AllRangePiecesCountActual * size= of (MTRR_MEMORY_RANGE)); >=20 > + *MemoryRangeCount =3D AllRangePiecesCountActual; >=20 > + >=20 > + free (AllEndPointsInclusive); >=20 > + free (AllRangePieces); >=20 > +} >=20 > diff --git a/UefiCpuPkg/Test/UefiCpuPkgHostTest.dsc b/UefiCpuPkg/Test/Uef= iCpuPkgHostTest.dsc > new file mode 100644 > index 0000000000..8a5c456830 > --- /dev/null > +++ b/UefiCpuPkg/Test/UefiCpuPkgHostTest.dsc > @@ -0,0 +1,31 @@ > +## @file >=20 > +# UefiCpuPkg DSC file used to build host-based unit tests. >=20 > +# >=20 > +# Copyright (c) 2020, Intel Corporation. All rights reserved.
>=20 > +# SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +# >=20 > +## >=20 > + >=20 > +[Defines] >=20 > + PLATFORM_NAME =3D UefiCpuPkgHostTest >=20 > + PLATFORM_GUID =3D E00B9599-5B74-4FF7-AB9F-8183FB13B2F9 >=20 > + PLATFORM_VERSION =3D 0.1 >=20 > + DSC_SPECIFICATION =3D 0x00010005 >=20 > + OUTPUT_DIRECTORY =3D Build/UefiCpuPkg/HostTest >=20 > + SUPPORTED_ARCHITECTURES =3D IA32|X64 >=20 > + BUILD_TARGETS =3D NOOPT >=20 > + SKUID_IDENTIFIER =3D DEFAULT >=20 > + >=20 > +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc >=20 > + >=20 > +[LibraryClasses] >=20 > + MtrrLib|UefiCpuPkg/Library/MtrrLib/MtrrLib.inf >=20 > + >=20 > +[PcdsPatchableInModule] >=20 > + gUefiCpuPkgTokenSpaceGuid.PcdCpuNumberOfReservedVariableMtrrs|0 >=20 > + >=20 > +[Components] >=20 > + # >=20 > + # Build HOST_APPLICATION that tests the MtrrLib >=20 > + # >=20 > + UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTestHost.inf >=20 > diff --git a/UefiCpuPkg/UefiCpuPkg.ci.yaml b/UefiCpuPkg/UefiCpuPkg.ci.yam= l > index 99e460a8b0..4559b40105 100644 > --- a/UefiCpuPkg/UefiCpuPkg.ci.yaml > +++ b/UefiCpuPkg/UefiCpuPkg.ci.yaml > @@ -8,6 +8,10 @@ > "CompilerPlugin": { >=20 > "DscPath": "UefiCpuPkg.dsc" >=20 > }, >=20 > + ## options defined ci/Plugin/HostUnitTestCompilerPlugin >=20 > + "HostUnitTestCompilerPlugin": { >=20 > + "DscPath": "Test/UefiCpuPkgHostTest.dsc" >=20 > + }, >=20 > "CharEncodingCheck": { >=20 > "IgnoreFiles": [] >=20 > }, >=20 > @@ -18,7 +22,9 @@ > "UefiCpuPkg/UefiCpuPkg.dec" >=20 > ], >=20 > # For host based unit tests >=20 > - "AcceptableDependencies-HOST_APPLICATION":[], >=20 > + "AcceptableDependencies-HOST_APPLICATION":[ >=20 > + "UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec" >=20 > + ], >=20 > # For UEFI shell based apps >=20 > "AcceptableDependencies-UEFI_APPLICATION":[], >=20 > "IgnoreInf": [] >=20 > @@ -30,6 +36,10 @@ > "UefiCpuPkg/ResetVector/Vtf0/Vtf0.inf" >=20 > ] >=20 > }, >=20 > + "HostUnitTestDscCompleteCheck": { >=20 > + "IgnoreInf": [""], >=20 > + "DscPath": "Test/UefiCpuPkgHostTest.dsc" >=20 > + }, >=20 > "GuidCheck": { >=20 > "IgnoreGuidName": ["SecCore", "ResetVector"], # Expected duplica= tion for gEfiFirmwareVolumeTopFileGuid >=20 > "IgnoreGuidValue": [], >=20 > -- > 2.27.0.windows.1 >=20 >=20 > -=3D-=3D-=3D-=3D-=3D-=3D > Groups.io Links: You receive all messages sent to this group. >=20 > View/Reply Online (#63380): https://edk2.groups.io/g/devel/message/63380 > Mute This Topic: https://groups.io/mt/75837117/1712937 > Group Owner: devel+owner@edk2.groups.io > Unsubscribe: https://edk2.groups.io/g/devel/unsub [ray.ni@intel.com] > -=3D-=3D-=3D-=3D-=3D-=3D