From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out03.hibox.biz (out03.hibox.biz [210.71.195.41]) by mx.groups.io with SMTP id smtpd.web10.17528.1595956425680890948 for ; Tue, 28 Jul 2020 10:13:47 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: insyde.com, ip: 210.71.195.41, mailfrom: tim.lewis@insyde.com) IronPort-SDR: 18jL86uUYPfUZpEJwkiM+c1Gdqi1dhpRUj+QKtxQ2ihNammamV7LqbwWoM3n+A+3dF9mbyAFMM hZrzLkBqN3xQ== X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A2BMAAANXCBf/ww0GKxWChkBAQEBAQE?= =?us-ascii?q?BAQEBAQEBAQEBAQESAQEBAQEBAQEBAQEBQAeBQ4F7gR5UX4Q0iQGIHoEBjjc?= =?us-ascii?q?UPIobgWkLAQEBAQEBAQEBCCMJAQIEAQGERgQCAoIhJTgTAgMBAQsBAQYBAQE?= =?us-ascii?q?BAQYEhkkMhXEBAQUIAhABCAQnCBwHDAEFBgMNBAQBAQECAiYCGxgeCAIEARI?= =?us-ascii?q?LBQQJBIMGgnwPrmB2fzMaAoQfAYYvgQ4qAYERU4RWgkaGFoERghJJNT6BDoJ?= =?us-ascii?q?yBAwFgz6CYASPOAgKBiGCNYc8KYE/gQ+INpBkB4s6hjqKXiGCe4EijT8DEY1?= =?us-ascii?q?5kheKLpUUgWqBenCDOQk2ERmONxcUbgEOhSGCBYYNJDACNQIGCAEBAwl0CBU?= =?us-ascii?q?BjSABgkUBAQ?= X-IronPort-AV: E=Sophos;i="5.75,406,1589212800"; d="scan'208";a="35967812" Received: from unknown (HELO hb3-BKT202.hibox.biz) ([172.24.52.12]) by out03.hibox.biz with ESMTP; 29 Jul 2020 01:13:41 +0800 IronPort-SDR: WuSuW4IA4ynNNgsoJFHA9lNvENDqKy08JcRO7wwSOUjt+gJaz0mmejlzGNCjJnjIUKfSPOONbx 1lOd7/W/GXKQ== Received: from unknown (HELO hb3-BKT101.hibox.biz) ([172.24.51.11]) by hb3-BKT202.hibox.biz with ESMTP; 29 Jul 2020 01:13:42 +0800 IronPort-SDR: CfQbBzaaBe0YidjBwZd44HA2BCqGbLnt3DeZPCJGny/n/mdNAMhqz5YTAPZdrPl+Lbj7ljZ3+I WAABltyw/hug== Received: from unknown (HELO hb3-IN02.hibox.biz) ([172.24.12.12]) by hb3-BKT101.hibox.biz with ESMTP; 29 Jul 2020 01:13:40 +0800 IronPort-SDR: 47gxXe6eKE4+6UKlza5rgaLoZQ7/0eGcEGLP7dziAI55Y3NT8gdji8q//RF3goO2maXw/6cJHI PJk5+ANmnz+r8S15k32IWYh7VgYwvH44w= X-Remote-IP: 73.116.1.175 X-Remote-Host: c-73-116-1-175.hsd1.ca.comcast.net X-SBRS: -10.0 X-MID: 41454340 X-Auth-ID: tim.lewis@insyde.com X-EnvelopeFrom: tim.lewis@insyde.com hiBox-Sender: 1 Received: from c-73-116-1-175.hsd1.ca.comcast.net (HELO DESKTOPHG9V3E8) ([73.116.1.175]) by hb3-IN02.hibox.biz with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Jul 2020 01:13:22 +0800 From: "Tim Lewis" To: , , Cc: "'Michael D Kinney'" , "'Ming Shao'" , "'Eric Dong'" , "'Laszlo Ersek'" , "'Sean Brogan'" , "'Bret Barkelew'" , "'Jiewen Yao'" In-Reply-To: Subject: Re: [edk2-devel] [PATCH v4] UefiCpuPkg/MtrrLib/UnitTest: Add host based unit test Date: Tue, 28 Jul 2020 10:13:21 -0700 Message-ID: <04ae01d66502$67338d20$359aa760$@insyde.com> MIME-Version: 1.0 X-Mailer: Microsoft Outlook 16.0 Thread-Index: AQKF7pMYm2g6kbGs9tmvBIsHLKIh7Ke+Jvvw Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Content-Language: en-us Sean -- What I have seen done for fuzz testing is to (a) report the seed used to i= nitialize the RNG in the log and then (b) provide an option to force the se= ed to that value. Using a static seed might actually be the default for CI = runs, but stand-alone runs could use a random value.=20 Just a thought. Tim -----Original Message----- From: devel@edk2.groups.io On Behalf Of Sean Sent: Tuesday, July 28, 2020 9:38 AM To: devel@edk2.groups.io; ray.ni@intel.com Cc: Michael D Kinney ; Ming Shao ; Eric Dong ; Laszlo Ersek = ; Sean Brogan ; Bret Barkelew ; Jiewen Yao Subject: Re: [edk2-devel] [PATCH v4] UefiCpuPkg/MtrrLib/UnitTest: Add host= based unit test Ray, I worry that this style of testing will lead to inconsistant results.=20 Generating random test cases means that the test cases on any given run=20 could find a bug in this code without this code changing. I think this= =20 type of testing (fuzz testing like) is great but I think we might want=20 to consider this a different test type and treat it differently. For unit testing the mtrr lib it would make more sense to identify a few= =20 unique passing and failing tests and statically add those. If there are= =20 edge cases or more cases needed to get full code coverage then=20 developing those would be great. Another point is once we start tracking code coverage your random test=20 generation will lead to different results which will make it hard to=20 track the metrics reliably. Finally, if edk2 community wants to support fuzz testing (which i think=20 is good) we should add details about how to add fuzz testing to edk2 and= =20 how to exclude it from PR/CI test runs. Thoughts? Thanks Sean On 7/28/2020 1:43 AM, Ni, Ray wrote: > 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 | 1139 +++++++++++++++++ > .../MtrrLib/UnitTest/MtrrLibUnitTest.h | 182 +++ > .../MtrrLib/UnitTest/MtrrLibUnitTestHost.inf | 39 + > UefiCpuPkg/Library/MtrrLib/UnitTest/Support.c | 923 +++++++++++++ > UefiCpuPkg/Test/UefiCpuPkgHostTest.dsc | 31 + > UefiCpuPkg/UefiCpuPkg.ci.yaml | 12 +- > 6 files changed, 2325 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/MtrrLibUnitTest= Host.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/Uef= iCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.c > new file mode 100644 > index 0000000000..123e1c741a > --- /dev/null > +++ b/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.c > @@ -0,0 +1,1139 @@ > +/** @file >=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 r= eturn 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, ActualRan= ges[Index].BaseAddress); >=20 > + UT_ASSERT_EQUAL (ExpectedMemoryRanges[Index].Length, ActualRanges[I= ndex].Length); >=20 > + UT_ASSERT_EQUAL (ExpectedMemoryRanges[Index].Type, ActualRanges[Ind= ex].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].Bas= eAddress, 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 faile= d. >=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_= MTRR]; >=20 > + MTRR_MEMORY_RANGE ExpectedMemoryRanges[MTRR_NUMBER_OF_F= IXED_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_FIX= ED_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 (PcdCpuNumberOfR= eservedVariableMtrrs), >=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, WcCo= unt >=20 > + ); >=20 > + UT_LOG_INFO ("--- Expected Memory Ranges [%d] ---\n", ExpectedMemoryR= angesCount); >=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->PhysicalAddre= ssBits, SystemParameter->VariableMtrrCount, >=20 > + &LocalMtrrs, ActualMemoryRanges, &ActualMemoryRangesCount, &Actua= lVariableMtrrUsage >=20 > + ); >=20 > + >=20 > + UT_LOG_INFO ("--- Actual Memory Ranges [%d] ---\n", ActualMemoryRan= gesCount); >=20 > + DumpMemoryRanges (ActualMemoryRanges, ActualMemoryRangesCount); >=20 > + VerifyMemoryRanges (ExpectedMemoryRanges, ExpectedMemoryRangesCount= , ActualMemoryRanges, ActualMemoryRangesCount); >=20 > + UT_ASSERT_TRUE (ExpectedVariableMtrrUsage >=3D ActualVariableMtrrUs= age); >=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].Ty= pe >=20 > + ); >=20 > + UT_ASSERT_TRUE (RETURN_ERROR (Status)); >=20 > + } >=20 > + >=20 > + ScratchSize =3D 0; >=20 > + Status =3D MtrrSetMemoryAttributesInMtrrSettings (NULL, NULL, &Scratc= hSize, 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 faile= d. >=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 (Sys= temParameter)); >=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 MTRR= s. >=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 faile= d. >=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 (Sys= temParameter)); >=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.Variabl= eMtrrCount <=3D MTRR_NUMBER_OF_VARIABLE_MTRR; SystemParameter.VariableMtrrC= ount++) { >=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 = ASSERT() >=20 > + // is generated. >=20 > + // >=20 > + SystemParameter.MtrrSupported =3D TRUE; >=20 > + for (SystemParameter.VariableMtrrCount =3D 1; SystemParameter.Variabl= eMtrrCount <=3D MTRR_NUMBER_OF_VARIABLE_MTRR; SystemParameter.VariableMtrrC= ount++) { >=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_VARIABL= E_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 faile= d. >=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 (Sys= temParameter)); >=20 > + >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + // >=20 > + // Positive test cases for VCNT =3D 10 and Reserved PCD in range 0..1= 0 >=20 > + // >=20 > + for (ReservedMtrrs =3D 0; ReservedMtrrs <=3D SystemParameter.Variable= MtrrCount; ReservedMtrrs++) { >=20 > + PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, ReservedMtrrs); >=20 > + Result =3D GetFirmwareVariableMtrrCount (); >=20 > + UT_ASSERT_EQUAL (Result, SystemParameter.VariableMtrrCount - Reserv= edMtrrs); >=20 > + } >=20 > + >=20 > + // >=20 > + // Negative test cases when Reserved PCD is larger than VCNT >=20 > + // >=20 > + for (ReservedMtrrs =3D SystemParameter.VariableMtrrCount + 1; Reserve= dMtrrs <=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_VARIABL= E_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 faile= d. >=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 faile= d. >=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 (Sys= temParameter)); >=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); MsrI= ndex++) { >=20 > + MsrValue =3D 0; >=20 > + for (ByteIndex =3D 0; ByteIndex < sizeof (UINT64); ByteIndex++) { >=20 > + MsrValue =3D MsrValue | LShiftU64 (GenerateRandomCacheType (), = ByteIndex * 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 (= ExpectedFixedSettings)); >=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 faile= d. >=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 (Sys= temParameter)); >=20 > + InitializeMtrrRegs (&SystemParameter); >=20 > + >=20 > + for (Index =3D 0; Index < SystemParameter.VariableMtrrCount; Index++)= { >=20 > + GenerateRandomMtrrPair (SystemParameter.PhysicalAddressBits, Genera= teRandomCacheType (), &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_VARIABL= E_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 faile= d. >=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 (Sys= temParameter)); >=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, Genera= teRandomCacheType (), &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.MtrrDef= Type); >=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 faile= d. >=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_VARIAB= LE_MTRR]; >=20 > + VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_= MTRR]; >=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 (Sys= temParameter)); >=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, Genera= teRandomCacheType (), &VariableSetting[Index], NULL); >=20 > + AsmWriteMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1), VariableSett= ing[Index].Base); >=20 > + AsmWriteMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1), VariableSett= ing[Index].Mask); >=20 > + } >=20 > + Result =3D MtrrGetMemoryAttributeInVariableMtrr (ValidMtrrBitsMask, V= alidMtrrAddressMask, 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) & ValidMtrrBit= sMask; >=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, V= alidMtrrAddressMask, VariableMtrr); >=20 > + UT_ASSERT_EQUAL (Result, 0); >=20 > + >=20 > + // >=20 > + // Expect ASSERT() if variable MTRR count is > MTRR_NUMBER_OF_VARIABL= E_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 (Valid= MtrrBitsMask, 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 faile= d. >=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 faile= d. >=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 (Sys= temParameter)); >=20 > + // >=20 > + // If MTRRs are supported, then always return the cache type in the M= SR >=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 faile= d. >=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_= MTRR]; >=20 > + MTRR_MEMORY_RANGE ExpectedMemoryRanges[MTRR_NUMBER_OF_F= IXED_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_FIX= ED_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 (PcdCpuNumberOfR= eservedVariableMtrrs), >=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", ExpectedMemoryR= angesCount); >=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 RET= URN_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->PhysicalAddre= ssBits, SystemParameter->VariableMtrrCount, >=20 > + &LocalMtrrs, ActualMemoryRanges, &ActualMemoryRangesCount, &Actua= lVariableMtrrUsage >=20 > + ); >=20 > + UT_LOG_INFO ("--- Actual Memory Ranges [%d] ---\n", ActualMemoryRan= gesCount); >=20 > + DumpMemoryRanges (ActualMemoryRanges, ActualMemoryRangesCount); >=20 > + VerifyMemoryRanges (ExpectedMemoryRanges, ExpectedMemoryRangesCount= , ActualMemoryRanges, ActualMemoryRangesCount); >=20 > + UT_ASSERT_TRUE (ExpectedVariableMtrrUsage >=3D ActualVariableMtrrUs= age); >=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 PcdCpuNumberOfRese= rvedVariableMtrrs. >=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 (PcdCpu= NumberOfReservedVariableMtrrs); >=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 PcdCpuNumberOfRese= rvedVariableMtrrs. >=20 > +**/ >=20 > +VOID >=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->Num= berOfReservedVariableMtrrs); >=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 MtrrSetMemoryAttr= ibuteInMtrrSettings >=20 > + and MtrrSetMemoryAttributesInMtrrSetti= ngs using random inputs. >=20 > + >=20 > + @retval EFI_SUCCESS All test cases were dispatched. >=20 > + @retval EFI_OUT_OF_RESOURCES There are not enough resources availab= le 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 GetFirmwareVariable= MtrrCountContext; >=20 > + >=20 > + Context.SystemParameter =3D &mDefaultSyst= emParameter; >=20 > + GetFirmwareVariableMtrrCountContext.SystemParameter =3D &mDefaultSyst= emParameter; >=20 > + Framework =3D NULL; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VER= SION)); >=20 > + >=20 > + // >=20 > + // Setup the test framework for running the tests. >=20 > + // >=20 > + Status =3D InitUnitTestFramework (&Framework, UNIT_TEST_APP_NAME, gEf= iCallerBaseName, 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 AP= I 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", UnitTestGetFirmwareVariableMtrrC= ount, SavePcdValue, RestorePcdValue, &GetFirmwareVariableMtrrCountC= ontext); >=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", UnitTestMtrrGetMemoryAttributeIn= VariableMtrr, 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", UnitTestInvalidMemoryLayou= ts, InitializeSystem, NULL, &mSystemParameters[SystemIndex= ]); >=20 > + AddTestCase (MtrrApiTests, "Test MtrrSetMemoryAttributeInMtrrSett= ings", "MtrrSetMemoryAttributeInMtrrSettings", UnitTestMtrrSetMemoryAttri= buteInMtrrSettings, InitializeSystem, NULL, &mSystemParameters[SystemIndex= ]); >=20 > + AddTestCase (MtrrApiTests, "Test MtrrSetMemoryAttributesInMtrrSet= tings", "MtrrSetMemoryAttributesInMtrrSettings", UnitTestMtrrSetMemoryAttri= butesInMtrrSettings, InitializeSystem, 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/Uef= iCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.h > new file mode 100644 > index 0000000000..9750523133 > --- /dev/null > +++ b/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.h > @@ -0,0 +1,182 @@ > +/** @file >=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 regist= ers initialization. >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +InitializeMtrrRegs ( >=20 > + IN MTRR_LIB_SYSTEM_PARAMETER *SystemParameter >=20 > + ); >=20 > + >=20 > +/** >=20 > + Initialize the MTRR registers. >=20 > + >=20 > + @param Context System parameter that controls the MTRR registers init= ialization. >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +InitializeSystem ( >=20 > + IN UNIT_TEST_CONTEXT Context >=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 = used. >=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-0509084376= AB >=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 t= he 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 ## SO= METIMES_CONSUMES >=20 > diff --git a/UefiCpuPkg/Library/MtrrLib/UnitTest/Support.c b/UefiCpuPkg/= Library/MtrrLib/UnitTest/Support.c > new file mode 100644 > index 0000000000..a7eed45940 > --- /dev/null > +++ b/UefiCpuPkg/Library/MtrrLib/UnitTest/Support.c > @@ -0,0 +1,923 @@ > +/** @file >=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, CacheWriteP= rotected, CacheWriteBack >=20 > + }; >=20 > + >=20 > +UINT64 mFixedMtrrsValue[MTRR_NUMBER_OF_FIXED_= MTRR]; >=20 > +MSR_IA32_MTRR_PHYSBASE_REGISTER mVariableMtrrsPhysBase[MTRR_NUMBER_OF_= VARIABLE_MTRR]; >=20 > +MSR_IA32_MTRR_PHYSMASK_REGISTER mVariableMtrrsPhysMask[MTRR_NUMBER_OF_= VARIABLE_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 = Eax. >=20 > + If Ebx is not NULL, then the value of EBX after CPUID is returned in = Ebx. >=20 > + If Ecx is not NULL, then the value of ECX after CPUID is returned in = Ecx. >=20 > + If Edx is not NULL, then the value of EDX after CPUID is returned in = Edx. >=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 CPU= ID >=20 > + instruction. This is an optional parameter that may be = NULL. >=20 > + @param Ebx The pointer to the 32-bit EBX value returned by the CPU= ID >=20 > + instruction. This is an optional parameter that may be = NULL. >=20 > + @param Ecx The pointer to the 32-bit ECX value returned by the CPU= ID >=20 > + instruction. This is an optional parameter that may be = NULL. >=20 > + @param Edx The pointer to the 32-bit EDX value returned by the CPU= ID >=20 > + instruction. This is an optional parameter that may be = NULL. >=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 che= cking is >=20 > + performed on Index, and some Index values may cause CPU exceptions. T= he >=20 > + caller must either guarantee that Index is valid, or the caller must = set up >=20 > + exception handlers to catch the exceptions. This function is only ava= ilable >=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 return= s the >=20 > + value. >=20 > + >=20 > + Writes the 64-bit value specified by Value to the MSR specified by In= dex. 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 exceptio= ns. The >=20 > + caller must either guarantee that Index and Value are valid, or the c= aller >=20 > + must establish proper exception handlers. This function is only avail= able 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 the MTRR registers. >=20 > + >=20 > + @param SystemParameter System parameter that controls the MTRR regist= ers 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->D= efaultCacheType; >=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 SystemParamet= er->MtrrSupported; >=20 > + mCpuidVirPhyAddressSizeEax.Bits.PhysicalAddressBits =3D SystemParamet= er->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 UnitTestMtrrLibAsmReadMsr= 64; >=20 > + gUnitTestHostBaseLib.X86->AsmWriteMsr64 =3D UnitTestMtrrLibAsmWriteMs= r64; >=20 > + >=20 > + return UNIT_TEST_PASSED; >=20 > +} >=20 > + >=20 > +/** >=20 > + Initialize the MTRR registers. >=20 > + >=20 > + @param Context System parameter that controls the MTRR registers init= ialization. >=20 > +**/ >=20 > +UNIT_TEST_STATUS >=20 > +EFIAPI >=20 > +InitializeSystem ( >=20 > + IN UNIT_TEST_CONTEXT Context >=20 > + ) >=20 > +{ >=20 > + return InitializeMtrrRegs ((MTRR_LIB_SYSTEM_PARAMETER *) Context); >=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 = used. >=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[Ind= ex].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[Ind= ex].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, RawMemory= Ranges, *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)) + S= tart; >=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)) + S= tart; >=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 - Base= Shift)); >=20 > + RangeBase =3D RandomBoundary << BaseShift; >=20 > + } while (RangeBase < SIZE_1MB || RangeBase > MaxPhysicalAddress - 1); >=20 > + >=20 > + PhysBasePhyMaskValidBitsMask =3D (MaxPhysicalAddress - 1) & 0xfffffff= ffffff000ULL; >=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) & PhysBasePhyMaskValidBitsM= ask; >=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[Co= unt].BaseAddress < Range->BaseAddress + Range->Length) >=20 > + || (Ranges[Count].BaseAddress <=3D Range->BaseAddress && Range->Ba= seAddress < 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, NUL= L, &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, N= ULL, &RawMemoryRanges[Index]); >=20 > + while (RangesOverlap (&RawMemoryRanges[Index], &RawMemoryRanges[UcC= ount], 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, N= ULL, &RawMemoryRanges[Index]); >=20 > + while (RangesOverlap (&RawMemoryRanges[Index], &RawMemoryRanges[UcC= ount], 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, *Coun= t); >=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.Base= Address + 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 = ranges. >=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 (NewRangesCount= AtMost, 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].BaseAd= dress; >=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->T= ype =3D=3D CurrentRangeTypeInOldRanges) { >=20 > + CurrentRangeInNewRanges->Length +=3D OldRanges[OldRangesIndex].Le= ngth; >=20 > + } else { >=20 > + NewRanges[NewRangesCountActual].BaseAddress =3D OldRanges[OldRang= esIndex].BaseAddress; >=20 > + NewRanges[NewRangesCountActual].Length +=3D OldRanges[OldRang= esIndex].Length; >=20 > + NewRanges[NewRangesCountActual].Type =3D CurrentRangeTypeI= nOldRanges; >=20 > + while (OldRangesIndex + 1 < *EffectiveMtrrMemoryRangesCount && Ol= dRanges[OldRangesIndex + 1].Type =3D=3D CurrentRangeTypeInOldRanges) >=20 > + { >=20 > + OldRangesIndex++; >=20 > + NewRanges[NewRangesCountActual].Length +=3D OldRanges[OldRanges= Index].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 - CurrentRangeInNe= wRanges->BaseAddress + 1; >=20 > + } else { >=20 > + NewRanges[NewRangesCountActual].BaseAddress =3D OldLastRange.Base= Address + 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 (UINT= 64)); >=20 > + AllRangePiecesCountMax =3D RawMemoryRangeCount * 3 + 1; >=20 > + AllRangePieces =3D calloc (AllRangePiecesCountMax, sizeof = (MTRR_MEMORY_RANGE)); >=20 > + CollectEndpoints (AllEndPointsInclusive, &AllEndPointsCount, RawMemor= yRanges, RawMemoryRangeCount); >=20 > + >=20 > + for (Index =3D 0, AllRangePiecesCountActual =3D 0; Index < AllEndPoin= tsCount - 1; Index++) { >=20 > + OverlapBitFlag1 =3D GetOverlapBitFlag (RawMemoryRanges, RawMemoryRa= ngeCount, AllEndPointsInclusive[Index]); >=20 > + OverlapBitFlag2 =3D GetOverlapBitFlag (RawMemoryRanges, RawMemoryRa= ngeCount, AllEndPointsInclusive[Index + 1]); >=20 > + OverlapFlagRelation =3D CheckOverlapBitFlagsRelation (OverlapBitFla= g1, OverlapBitFlag2); >=20 > + switch (OverlapFlagRelation) { >=20 > + case 0: // [1, 2] >=20 > + AllRangePieces[AllRangePiecesCountActual].BaseAddress =3D AllEn= dPointsInclusive[Index]; >=20 > + AllRangePieces[AllRangePiecesCountActual].Length =3D AllEn= dPointsInclusive[Index + 1] - AllEndPointsInclusive[Index] + 1; >=20 > + AllRangePiecesCountActual++; >=20 > + break; >=20 > + case 1: // [1, 2) >=20 > + AllRangePieces[AllRangePiecesCountActual].BaseAddress =3D AllEn= dPointsInclusive[Index]; >=20 > + AllRangePieces[AllRangePiecesCountActual].Length =3D (AllE= ndPointsInclusive[Index + 1] - 1) - AllEndPointsInclusive[Index] + 1; >=20 > + AllRangePiecesCountActual++; >=20 > + break; >=20 > + case 2: // (1, 2] >=20 > + AllRangePieces[AllRangePiecesCountActual].BaseAddress =3D AllEn= dPointsInclusive[Index] + 1; >=20 > + AllRangePieces[AllRangePiecesCountActual].Length =3D AllEn= dPointsInclusive[Index + 1] - (AllEndPointsInclusive[Index] + 1) + 1; >=20 > + AllRangePiecesCountActual++; >=20 > + >=20 > + if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRange= Pieces, AllRangePiecesCountActual)) { >=20 > + AllRangePieces[AllRangePiecesCountActual].BaseAddress =3D All= EndPointsInclusive[Index]; >=20 > + AllRangePieces[AllRangePiecesCountActual].Length =3D 1; >=20 > + AllRangePiecesCountActual++; >=20 > + } >=20 > + break; >=20 > + case 3: // (1, 2) >=20 > + AllRangePieces[AllRangePiecesCountActual].BaseAddress =3D AllEn= dPointsInclusive[Index] + 1; >=20 > + AllRangePieces[AllRangePiecesCountActual].Length =3D (AllE= ndPointsInclusive[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], AllRange= Pieces, AllRangePiecesCountActual)) { >=20 > + AllRangePieces[AllRangePiecesCountActual].BaseAddress =3D All= EndPointsInclusive[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], RawM= emoryRanges, RawMemoryRangeCount); >=20 > + } >=20 > + >=20 > + CompactAndExtendEffectiveMtrrMemoryRanges (DefaultType, PhysicalAddre= ssBits, &AllRangePieces, &AllRangePiecesCountActual); >=20 > + ASSERT (*MemoryRangeCount >=3D AllRangePiecesCountActual); >=20 > + memcpy (MemoryRanges, AllRangePieces, AllRangePiecesCountActual * siz= eof (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/Ue= fiCpuPkgHostTest.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.ya= ml > 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 dupli= cation for gEfiFirmwareVolumeTopFileGuid >=20 > "IgnoreGuidValue": [], >=20