Reviewed-by: Eric Dong <eric.d...@intel.com>

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


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#63280): https://edk2.groups.io/g/devel/message/63280
Mute This Topic: https://groups.io/mt/75761809/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to