Add host based unit tests for the CpuPageTableLib services. Unit test focuses on PageTableMap function, containing two kinds of test cases: manual test case and random test case. Manual test case creates some corner case to test function PageTableMap. Random test case generates multiple random memory entries (with random attribute) as the input of function PageTableMap to get the output pagetable. Output pagetable will be validated and be parsed to get output memory entries, and then the input and output memory entries will be compared to verify the functionality. The unit test is not perfect yet. There are options for random test, and some of them control the test coverage, and some option are not ready. Will enhance in the future. Cc: Eric Dong <eric.dong@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Signed-off-by: Zhiguang Liu <zhiguang.liu@intel.com>
		
			
				
	
	
		
			927 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			927 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Random test case for Unit tests of the CpuPageTableLib instance of the CpuPageTableLib class
 | |
| 
 | |
|   Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "CpuPageTableLibUnitTest.h"
 | |
| #include "RandomTest.h"
 | |
| 
 | |
| UINTN                     RandomNumber = 0;
 | |
| extern IA32_PAGING_ENTRY  mValidMaskNoLeaf[6];
 | |
| extern IA32_PAGING_ENTRY  mValidMaskLeaf[6];
 | |
| extern IA32_PAGING_ENTRY  mValidMaskLeafFlag[6];
 | |
| UINTN                     mRandomOption;
 | |
| IA32_MAP_ATTRIBUTE        mSupportedBit;
 | |
| extern UINTN              mNumberCount;
 | |
| extern UINT8              mNumbers[];
 | |
| UINTN                     mNumberIndex;
 | |
| UINT64                    AlignedTable[] = {
 | |
|   ~((UINT64)SIZE_4KB - 1),
 | |
|   ~((UINT64)SIZE_2MB - 1),
 | |
|   ~((UINT64)SIZE_1GB - 1)
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Generates a pseudorandom byte stream of the specified size.
 | |
| 
 | |
|   Return FALSE to indicate this interface is not supported.
 | |
| 
 | |
|   @param[out]  Output  Pointer to buffer to receive random value.
 | |
|   @param[in]   Size    Size of random bytes to generate.
 | |
| 
 | |
|   @retval TRUE   Always return TRUE
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| RandomBytesUsingArray (
 | |
|   OUT  UINT8  *Output,
 | |
|   IN   UINTN  Size
 | |
|   )
 | |
| {
 | |
|   UINTN  Index;
 | |
| 
 | |
|   for (Index = 0; Index < Size; Index++) {
 | |
|     if (mNumberIndex >= mNumberCount) {
 | |
|       mNumberIndex = 0;
 | |
|     }
 | |
| 
 | |
|     Output[Index] = mNumbers[mNumberIndex];
 | |
|     mNumberIndex++;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Generates a pseudorandom byte stream of the specified size.
 | |
| 
 | |
|   Return FALSE to indicate this interface is not supported.
 | |
| 
 | |
|   @param[out]  Output  Pointer to buffer to receive random value.
 | |
|   @param[in]   Size    Size of random bytes to generate.
 | |
| 
 | |
|   @retval TRUE   Pseudorandom byte stream generated successfully.
 | |
|   @retval FALSE  Pseudorandom number generator fails
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| LocalRandomBytes (
 | |
|   OUT  UINT8  *Output,
 | |
|   IN   UINTN  Size
 | |
|   )
 | |
| {
 | |
|   if (mRandomOption & USE_RANDOM_ARRAY) {
 | |
|     return RandomBytesUsingArray (Output, Size);
 | |
|   } else {
 | |
|     return RandomBytes (Output, Size);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Return a random boolean.
 | |
| 
 | |
|   @return boolean
 | |
| **/
 | |
| BOOLEAN
 | |
| RandomBoolean (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   BOOLEAN  Value;
 | |
| 
 | |
|   LocalRandomBytes ((UINT8 *)&Value, sizeof (BOOLEAN));
 | |
|   return Value%2;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Return a 32bit random number.
 | |
| 
 | |
|   @param Start  Start of the random number range.
 | |
|   @param Limit  Limit of the random number range, and return value can be Limit.
 | |
|   @return 32bit random number
 | |
| **/
 | |
| UINT32
 | |
| Random32 (
 | |
|   UINT32  Start,
 | |
|   UINT32  Limit
 | |
|   )
 | |
| {
 | |
|   UINT64  Value;
 | |
| 
 | |
|   LocalRandomBytes ((UINT8 *)&Value, sizeof (UINT64));
 | |
|   return (UINT32)(Value % (Limit - Start + 1)) + Start;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Return a 64bit random number.
 | |
| 
 | |
|   @param Start  Start of the random number range.
 | |
|   @param Limit  Limit of the random number range, and return value can be Limit.
 | |
|   @return 64bit random number
 | |
| **/
 | |
| UINT64
 | |
| Random64 (
 | |
|   UINT64  Start,
 | |
|   UINT64  Limit
 | |
|   )
 | |
| {
 | |
|   UINT64  Value;
 | |
| 
 | |
|   LocalRandomBytes ((UINT8 *)&Value, sizeof (UINT64));
 | |
|   if (Limit - Start  == MAX_UINT64) {
 | |
|     return (UINT64)(Value);
 | |
|   }
 | |
| 
 | |
|   return (UINT64)(Value % (Limit - Start  + 1)) + Start;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check if the Page table entry is valid
 | |
| 
 | |
|   @param[in]   PagingEntry    The entry in page table to verify
 | |
|   @param[in]   Level          the level of PagingEntry.
 | |
|   @param[in]   MaxLeafLevel   Max leaf entry level.
 | |
|   @param[in]   LinearAddress  The linear address verified.
 | |
| 
 | |
|   @retval  Leaf entry.
 | |
| **/
 | |
| UNIT_TEST_STATUS
 | |
| ValidateAndRandomeModifyPageTablePageTableEntry (
 | |
|   IN IA32_PAGING_ENTRY  *PagingEntry,
 | |
|   IN UINTN              Level,
 | |
|   IN UINTN              MaxLeafLevel,
 | |
|   IN UINT64             Address
 | |
|   )
 | |
| {
 | |
|   UINT64             Index;
 | |
|   UINT64             TempPhysicalBase;
 | |
|   IA32_PAGING_ENTRY  *ChildPageEntry;
 | |
|   UNIT_TEST_STATUS   Status;
 | |
| 
 | |
|   if (PagingEntry->Pce.Present == 0) {
 | |
|     return UNIT_TEST_PASSED;
 | |
|   }
 | |
| 
 | |
|   if ((PagingEntry->Uint64 & mValidMaskLeafFlag[Level].Uint64) == mValidMaskLeafFlag[Level].Uint64) {
 | |
|     //
 | |
|     // It is a Leaf
 | |
|     //
 | |
|     if (Level > MaxLeafLevel) {
 | |
|       UT_ASSERT_TRUE (Level <= MaxLeafLevel);
 | |
|     }
 | |
| 
 | |
|     if ((PagingEntry->Uint64 & mValidMaskLeaf[Level].Uint64) != PagingEntry->Uint64) {
 | |
|       UT_ASSERT_EQUAL ((PagingEntry->Uint64 & mValidMaskLeaf[Level].Uint64), PagingEntry->Uint64);
 | |
|     }
 | |
| 
 | |
|     if ((RandomNumber < 100) && RandomBoolean ()) {
 | |
|       RandomNumber++;
 | |
|       if (Level == 1) {
 | |
|         TempPhysicalBase = PagingEntry->Pte4K.Bits.PageTableBaseAddress;
 | |
|       } else {
 | |
|         TempPhysicalBase = PagingEntry->PleB.Bits.PageTableBaseAddress;
 | |
|       }
 | |
| 
 | |
|       PagingEntry->Uint64             = (Random64 (0, MAX_UINT64) & mValidMaskLeaf[Level].Uint64) | mValidMaskLeafFlag[Level].Uint64;
 | |
|       PagingEntry->Pte4K.Bits.Present = 1;
 | |
|       if (Level == 1) {
 | |
|         PagingEntry->Pte4K.Bits.PageTableBaseAddress = TempPhysicalBase;
 | |
|       } else {
 | |
|         PagingEntry->PleB.Bits.PageTableBaseAddress = TempPhysicalBase;
 | |
|       }
 | |
| 
 | |
|       if ((PagingEntry->Uint64 & mValidMaskLeaf[Level].Uint64) != PagingEntry->Uint64) {
 | |
|         UT_ASSERT_EQUAL ((PagingEntry->Uint64 & mValidMaskLeaf[Level].Uint64), PagingEntry->Uint64);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return UNIT_TEST_PASSED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Not a leaf
 | |
|   //
 | |
|   UT_ASSERT_NOT_EQUAL (Level, 1);
 | |
|   if ((PagingEntry->Uint64 & mValidMaskNoLeaf[Level].Uint64) != PagingEntry->Uint64) {
 | |
|     DEBUG ((DEBUG_ERROR, "ERROR: Level %d no Leaf entry is 0x%lx, which reserved bit is set \n", Level, PagingEntry->Uint64));
 | |
|     UT_ASSERT_EQUAL ((PagingEntry->Uint64 & mValidMaskNoLeaf[Level].Uint64), PagingEntry->Uint64);
 | |
|   }
 | |
| 
 | |
|   if ((RandomNumber < 100) && RandomBoolean ()) {
 | |
|     RandomNumber++;
 | |
|     TempPhysicalBase = PagingEntry->Pnle.Bits.PageTableBaseAddress;
 | |
| 
 | |
|     PagingEntry->Uint64                         = Random64 (0, MAX_UINT64) & mValidMaskNoLeaf[Level].Uint64;
 | |
|     PagingEntry->Pnle.Bits.Present              = 1;
 | |
|     PagingEntry->Pnle.Bits.PageTableBaseAddress = TempPhysicalBase;
 | |
|     ASSERT ((PagingEntry->Uint64 & mValidMaskLeafFlag[Level].Uint64) != mValidMaskLeafFlag[Level].Uint64);
 | |
|   }
 | |
| 
 | |
|   ChildPageEntry = (IA32_PAGING_ENTRY  *)(UINTN)((PagingEntry->Pnle.Bits.PageTableBaseAddress) << 12);
 | |
|   for (Index = 0; Index < 512; Index++) {
 | |
|     Status = ValidateAndRandomeModifyPageTablePageTableEntry (&ChildPageEntry[Index], Level-1, MaxLeafLevel, Address + (Index<<(9*(Level-1) + 3)));
 | |
|     if (Status != UNIT_TEST_PASSED) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return UNIT_TEST_PASSED;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check if the Page table is valid
 | |
| 
 | |
|   @param[in]   PageTable      The pointer to the page table.
 | |
|   @param[in]   PagingMode     The paging mode.
 | |
| 
 | |
|   @retval  UNIT_TEST_PASSED   It is a valid Page Table
 | |
| **/
 | |
| UNIT_TEST_STATUS
 | |
| ValidateAndRandomeModifyPageTable (
 | |
|   IN     UINTN        PageTable,
 | |
|   IN     PAGING_MODE  PagingMode
 | |
|   )
 | |
| {
 | |
|   UINTN              MaxLevel;
 | |
|   UINTN              MaxLeafLevel;
 | |
|   UINT64             Index;
 | |
|   UNIT_TEST_STATUS   Status;
 | |
|   IA32_PAGING_ENTRY  *PagingEntry;
 | |
| 
 | |
|   if ((PagingMode == Paging32bit) || (PagingMode == PagingPae) || (PagingMode >= PagingModeMax)) {
 | |
|     //
 | |
|     // 32bit paging is never supported.
 | |
|     // PAE paging will be supported later.
 | |
|     //
 | |
|     return UNIT_TEST_ERROR_TEST_FAILED;
 | |
|   }
 | |
| 
 | |
|   MaxLeafLevel = (UINT8)PagingMode;
 | |
|   MaxLevel     = (UINT8)(PagingMode >> 8);
 | |
| 
 | |
|   PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTable;
 | |
|   for (Index = 0; Index < 512; Index++) {
 | |
|     Status = ValidateAndRandomeModifyPageTablePageTableEntry (&PagingEntry[Index], MaxLevel, MaxLeafLevel, Index << (9 * MaxLevel + 3));
 | |
|     if (Status != UNIT_TEST_PASSED) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Generate single random map entry.
 | |
|   The map entry can be the input of function PageTableMap
 | |
|   the LinearAddress and length is aligned to aligned table.
 | |
| 
 | |
|   @param MaxAddress  Max Address.
 | |
|   @param MapEntrys   Output MapEntrys contains all parameter as input of function PageTableMap
 | |
| **/
 | |
| VOID
 | |
| GenerateSingleRandomMapEntry (
 | |
|   IN     UINT64      MaxAddress,
 | |
|   IN OUT MAP_ENTRYS  *MapEntrys
 | |
|   )
 | |
| {
 | |
|   UINTN   MapsIndex;
 | |
|   UINT64  FormerLinearAddress;
 | |
|   UINT64  FormerLinearAddressBottom;
 | |
|   UINT64  FormerLinearAddressTop;
 | |
| 
 | |
|   MapsIndex = MapEntrys->Count;
 | |
| 
 | |
|   ASSERT (MapsIndex < MapEntrys->MaxCount);
 | |
|   //
 | |
|   // use AlignedTable to avoid that a random number can be very hard to be 1G or 2M aligned
 | |
|   //
 | |
|   if ((MapsIndex != 0) &&  (RandomBoolean ())) {
 | |
|     FormerLinearAddress = MapEntrys->Maps[Random32 (0, (UINT32)MapsIndex-1)].LinearAddress;
 | |
|     if (FormerLinearAddress < 2 * (UINT64)SIZE_1GB) {
 | |
|       FormerLinearAddressBottom = 0;
 | |
|     } else {
 | |
|       FormerLinearAddressBottom = FormerLinearAddress - 2 * (UINT64)SIZE_1GB;
 | |
|     }
 | |
| 
 | |
|     if (FormerLinearAddress + 2 * (UINT64)SIZE_1GB > MaxAddress) {
 | |
|       FormerLinearAddressTop = MaxAddress;
 | |
|     } else {
 | |
|       FormerLinearAddressTop = FormerLinearAddress + 2 * (UINT64)SIZE_1GB;
 | |
|     }
 | |
| 
 | |
|     MapEntrys->Maps[MapsIndex].LinearAddress = Random64 (FormerLinearAddressBottom, FormerLinearAddressTop) & AlignedTable[Random32 (0, ARRAY_SIZE (AlignedTable) -1)];
 | |
|   } else {
 | |
|     MapEntrys->Maps[MapsIndex].LinearAddress = Random64 (0, MaxAddress) & AlignedTable[Random32 (0, ARRAY_SIZE (AlignedTable) -1)];
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // To have better performance, limit the size less than 10G
 | |
|   //
 | |
|   MapEntrys->Maps[MapsIndex].Length = Random64 (0, MIN (MaxAddress - MapEntrys->Maps[MapsIndex].LinearAddress, 10 * (UINT64)SIZE_1GB)) & AlignedTable[Random32 (0, ARRAY_SIZE (AlignedTable) -1)];
 | |
| 
 | |
|   if ((MapsIndex != 0)  && (RandomBoolean ())) {
 | |
|     MapEntrys->Maps[MapsIndex].Attribute.Uint64 = MapEntrys->Maps[Random32 (0, (UINT32)MapsIndex-1)].Attribute.Uint64;
 | |
|     MapEntrys->Maps[MapsIndex].Mask.Uint64      = MapEntrys->Maps[Random32 (0, (UINT32)MapsIndex-1)].Mask.Uint64;
 | |
|   } else {
 | |
|     MapEntrys->Maps[MapsIndex].Attribute.Uint64 = Random64 (0, MAX_UINT64) & mSupportedBit.Uint64;
 | |
|     MapEntrys->Maps[MapsIndex].Mask.Uint64      = Random64 (0, MAX_UINT64) & mSupportedBit.Uint64;
 | |
|     if (MapEntrys->Maps[MapsIndex].Mask.Bits.ProtectionKey != 0) {
 | |
|       MapEntrys->Maps[MapsIndex].Mask.Bits.ProtectionKey = 0xF;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (mRandomOption & ONLY_ONE_ONE_MAPPING) {
 | |
|     MapEntrys->Maps[MapsIndex].Attribute.Bits.PageTableBaseAddress = MapEntrys->Maps[MapsIndex].LinearAddress >> 12;
 | |
|     MapEntrys->Maps[MapsIndex].Mask.Bits.PageTableBaseAddress      = 0xFFFFFFFFFF;
 | |
|   } else {
 | |
|     //
 | |
|     // Todo: If the mask bit for base address is zero, when dump the pagetable, every entry mapping to physical address zeor.
 | |
|     //       This means the map count will be a large number, and impossible to finish in proper time.
 | |
|     //       Need to avoid such case when remove the Random option ONLY_ONE_ONE_MAPPING
 | |
|     //
 | |
|     MapEntrys->Maps[MapsIndex].Attribute.Bits.PageTableBaseAddress = (Random64 (0, (((UINT64)1)<<52) - 1) & AlignedTable[Random32 (0, ARRAY_SIZE (AlignedTable) -1)])>> 12;
 | |
|     if (RandomBoolean ()) {
 | |
|       MapEntrys->Maps[MapsIndex].Mask.Bits.PageTableBaseAddress = 0;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   MapEntrys->Count += 1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Compare the attribute for one point.
 | |
|   MapEntrys records every memory ranges that is used as input
 | |
|   Map and MapCount are gotten from Page table
 | |
|   Compare if this point have same attribute.
 | |
| 
 | |
|   @param[in] Address      Address of one Point.
 | |
|   @param[in] MapEntrys    Record every memory ranges that is used as input
 | |
|   @param[in] Map          Pointer to an array that describes multiple linear address ranges.
 | |
|   @param[in] MapCount     Pointer to a UINTN that hold the number of entries in the Map.
 | |
|   @param[in] InitMap      Pointer to an array that describes init map entries.
 | |
|   @param[in] InitMapCount Pointer to a UINTN that hold the number of init map entries.
 | |
| 
 | |
|   @retval TRUE          At least one byte of data is available to be read
 | |
|   @retval FALSE         No data is available to be read
 | |
| **/
 | |
| BOOLEAN
 | |
| CompareEntrysforOnePoint (
 | |
|   IN  UINT64          Address,
 | |
|   IN  MAP_ENTRYS      *MapEntrys,
 | |
|   IN  IA32_MAP_ENTRY  *Map,
 | |
|   IN  UINTN           MapCount,
 | |
|   IN  IA32_MAP_ENTRY  *InitMap,
 | |
|   IN  UINTN           InitMapCount
 | |
|   )
 | |
| {
 | |
|   UINTN               Index;
 | |
|   IA32_MAP_ATTRIBUTE  AttributeInInitMap;
 | |
|   IA32_MAP_ATTRIBUTE  AttributeInMap;
 | |
|   IA32_MAP_ATTRIBUTE  AttributeInMapEntrys;
 | |
|   IA32_MAP_ATTRIBUTE  MaskInMapEntrys;
 | |
| 
 | |
|   AttributeInMap.Uint64       = 0;
 | |
|   AttributeInMapEntrys.Uint64 = 0;
 | |
|   AttributeInInitMap.Uint64   = 0;
 | |
|   MaskInMapEntrys.Uint64      = 0;
 | |
|   //
 | |
|   // Assume every entry in maps does not overlap with each other
 | |
|   //
 | |
|   for (Index = 0; Index < MapCount; Index++) {
 | |
|     if ((Address >= Map[Index].LinearAddress) && (Address < (Map[Index].LinearAddress + Map[Index].Length))) {
 | |
|       AttributeInMap.Uint64                    = (Map[Index].Attribute.Uint64 & mSupportedBit.Uint64);
 | |
|       AttributeInMap.Bits.PageTableBaseAddress = ((Address - Map[Index].LinearAddress) >> 12) + Map[Index].Attribute.Bits.PageTableBaseAddress;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Assume every entry in maps does not overlap with each other
 | |
|   //
 | |
|   for (Index = 0; Index < InitMapCount; Index++) {
 | |
|     if ((Address >= InitMap[Index].LinearAddress) && (Address < (InitMap[Index].LinearAddress + InitMap[Index].Length))) {
 | |
|       AttributeInInitMap.Uint64                    = (InitMap[Index].Attribute.Uint64 & mSupportedBit.Uint64);
 | |
|       AttributeInInitMap.Bits.PageTableBaseAddress = ((Address - InitMap[Index].LinearAddress) >> 12) + InitMap[Index].Attribute.Bits.PageTableBaseAddress;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   AttributeInMapEntrys.Uint64 = AttributeInInitMap.Uint64;
 | |
| 
 | |
|   for (Index = MapEntrys->InitCount; Index < MapEntrys->Count; Index++) {
 | |
|     if ((Address >= MapEntrys->Maps[Index].LinearAddress) && (Address < (MapEntrys->Maps[Index].LinearAddress + MapEntrys->Maps[Index].Length))) {
 | |
|       if (AttributeInMapEntrys.Bits.Present == 0) {
 | |
|         AttributeInMapEntrys.Uint64 = 0;
 | |
|         MaskInMapEntrys.Uint64      = 0;
 | |
|       }
 | |
| 
 | |
|       MaskInMapEntrys.Uint64      |= MapEntrys->Maps[Index].Mask.Uint64;
 | |
|       AttributeInMapEntrys.Uint64 &= (~MapEntrys->Maps[Index].Mask.Uint64);
 | |
|       AttributeInMapEntrys.Uint64 |=  (MapEntrys->Maps[Index].Attribute.Uint64 & MapEntrys->Maps[Index].Mask.Uint64);
 | |
|       if (MapEntrys->Maps[Index].Mask.Bits.PageTableBaseAddress != 0) {
 | |
|         AttributeInMapEntrys.Bits.PageTableBaseAddress = ((Address - MapEntrys->Maps[Index].LinearAddress) >> 12) + MapEntrys->Maps[Index].Attribute.Bits.PageTableBaseAddress;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (AttributeInMap.Bits.Present == 0) {
 | |
|     if (AttributeInMapEntrys.Bits.Present == 0) {
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ((AttributeInMap.Uint64 & MaskInMapEntrys.Uint64) != (AttributeInMapEntrys.Uint64 & MaskInMapEntrys.Uint64)) {
 | |
|     DEBUG ((DEBUG_INFO, "======detailed information begin=====\n"));
 | |
|     DEBUG ((DEBUG_INFO, "\nError: Detect different attribute on a point with linear address: 0x%lx\n", Address));
 | |
|     DEBUG ((DEBUG_INFO, "By parsing page table, the point has Attribute 0x%lx, and map to physical address 0x%lx\n", IA32_MAP_ATTRIBUTE_ATTRIBUTES (&AttributeInMap) & MaskInMapEntrys.Uint64, AttributeInMap.Bits.PageTableBaseAddress));
 | |
|     DEBUG ((DEBUG_INFO, "While according to inputs, the point should Attribute 0x%lx, and should map to physical address 0x%lx\n", IA32_MAP_ATTRIBUTE_ATTRIBUTES (&AttributeInMapEntrys) & MaskInMapEntrys.Uint64, AttributeInMapEntrys.Bits.PageTableBaseAddress));
 | |
|     DEBUG ((DEBUG_INFO, "The total Mask is 0x%lx\n", MaskInMapEntrys.Uint64));
 | |
| 
 | |
|     if (MapEntrys->InitCount != 0) {
 | |
|       DEBUG ((DEBUG_INFO, "Below is the initialization status:\n"));
 | |
|       for (Index = 0; Index < InitMapCount; Index++) {
 | |
|         if ((Address >= InitMap[Index].LinearAddress) && (Address < (InitMap[Index].LinearAddress + InitMap[Index].Length))) {
 | |
|           DEBUG ((DEBUG_INFO, " *"));
 | |
|         } else {
 | |
|           DEBUG ((DEBUG_INFO, "  "));
 | |
|         }
 | |
| 
 | |
|         DEBUG ((DEBUG_INFO, "  %02d: {0x%lx, 0x%lx, 0x%lx}\n", Index, InitMap[Index].LinearAddress, InitMap[Index].LinearAddress + InitMap[Index].Length, InitMap[Index].Attribute.Uint64));
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     DEBUG ((DEBUG_INFO, "Below is the inputs:\n"));
 | |
|     DEBUG ((DEBUG_INFO, "  Index: {LinearAddress, LinearLimit, Mask, Attribute}\n"));
 | |
|     for (Index = MapEntrys->InitCount; Index < MapEntrys->Count; Index++) {
 | |
|       if ((Address >= MapEntrys->Maps[Index].LinearAddress) && (Address < (MapEntrys->Maps[Index].LinearAddress + MapEntrys->Maps[Index].Length))) {
 | |
|         DEBUG ((DEBUG_INFO, " *"));
 | |
|       } else {
 | |
|         DEBUG ((DEBUG_INFO, "  "));
 | |
|       }
 | |
| 
 | |
|       DEBUG ((
 | |
|         DEBUG_INFO,
 | |
|         "  %02d: {0x%lx, 0x%lx, 0x%lx,0x%lx}\n",
 | |
|         Index,
 | |
|         MapEntrys->Maps[Index].LinearAddress,
 | |
|         MapEntrys->Maps[Index].LinearAddress + MapEntrys->Maps[Index].Length,
 | |
|         MapEntrys->Maps[Index].Mask.Uint64,
 | |
|         MapEntrys->Maps[Index].Attribute.Uint64
 | |
|         ));
 | |
|     }
 | |
| 
 | |
|     DEBUG ((DEBUG_INFO, "Below is the dumped from pagetable:\n"));
 | |
|     for (Index = 0; Index < MapCount; Index++) {
 | |
|       if ((Address >= Map[Index].LinearAddress) && (Address < (Map[Index].LinearAddress + Map[Index].Length))) {
 | |
|         DEBUG ((DEBUG_INFO, " *"));
 | |
|       } else {
 | |
|         DEBUG ((DEBUG_INFO, "  "));
 | |
|       }
 | |
| 
 | |
|       DEBUG ((DEBUG_INFO, "%02d: {0x%lx, 0x%lx, 0x%lx}\n", Index, Map[Index].LinearAddress, Map[Index].LinearAddress + Map[Index].Length, Map[Index].Attribute.Uint64));
 | |
|     }
 | |
| 
 | |
|     DEBUG ((DEBUG_INFO, "======detailed information done=====\n"));
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Append key point of a given address to Buffer
 | |
|   if buffer is NULL, only count needed count
 | |
| 
 | |
|   @param[in, out] Buffer  Buffer to contains all key point.
 | |
|   @param[in, out] Count   Count of the key point.
 | |
|   @param[in]      Address given address
 | |
| **/
 | |
| VOID
 | |
| AppendKeyPointToBuffer (
 | |
|   IN OUT UINT64  *Buffer,
 | |
|   IN OUT UINTN   *Count,
 | |
|   IN     UINT64  Address
 | |
|   )
 | |
| {
 | |
|   if ( Buffer != NULL) {
 | |
|     Buffer[*Count] = Address;
 | |
|     (*Count)++;
 | |
|     Buffer[*Count] = Address+1;
 | |
|     (*Count)++;
 | |
|     Buffer[*Count] = Address-1;
 | |
|     (*Count)++;
 | |
|   } else {
 | |
|     (*Count) = (*Count) +3;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get all key points from a buffer
 | |
|   if buffer is NULL, only count needed count
 | |
| 
 | |
|   @param[in] MapEntrys    Record every memory ranges that is used as input
 | |
|   @param[in] Map          Pointer to an array that describes multiple linear address ranges.
 | |
|   @param[in] MapCount     Pointer to a UINTN that hold the actual number of entries in the Map.
 | |
|   @param[in, out] Buffer  Buffer to contains all key point.
 | |
|   @param[in, out] Count   Count of the key point.
 | |
| **/
 | |
| VOID
 | |
| GetKeyPointList (
 | |
|   IN     MAP_ENTRYS      *MapEntrys,
 | |
|   IN     IA32_MAP_ENTRY  *Map,
 | |
|   IN     UINTN           MapCount,
 | |
|   IN OUT UINT64          *Buffer,
 | |
|   IN OUT UINTN           *Count
 | |
|   )
 | |
| {
 | |
|   UINTN  TemCount;
 | |
|   UINTN  Index1;
 | |
|   UINTN  Index2;
 | |
| 
 | |
|   TemCount = 0;
 | |
| 
 | |
|   for (Index1 = 0; Index1 < MapEntrys->Count; Index1++) {
 | |
|     AppendKeyPointToBuffer (Buffer, &TemCount, MapEntrys->Maps[Index1].LinearAddress);
 | |
|     AppendKeyPointToBuffer (Buffer, &TemCount, MapEntrys->Maps[Index1].LinearAddress + MapEntrys->Maps[Index1].Length);
 | |
|   }
 | |
| 
 | |
|   for (Index2 = 0; Index2 < MapCount; Index2++) {
 | |
|     if (Buffer != NULL) {
 | |
|       for (Index1 = 0; Index1 < TemCount; Index1++) {
 | |
|         if (Buffer[Index1] == Map[Index2].LinearAddress) {
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (Index1 < TemCount) {
 | |
|         continue;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     AppendKeyPointToBuffer (Buffer, &TemCount, Map[Index2].LinearAddress);
 | |
|   }
 | |
| 
 | |
|   for (Index2 = 0; Index2 < MapCount; Index2++) {
 | |
|     if (Buffer != NULL) {
 | |
|       for (Index1 = 0; Index1 < TemCount; Index1++) {
 | |
|         if (Buffer[Index1] == (Map[Index2].LinearAddress + Map[Index2].Length)) {
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (Index1 < TemCount) {
 | |
|         continue;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     AppendKeyPointToBuffer (Buffer, &TemCount, Map[Index2].LinearAddress + Map[Index2].Length);
 | |
|   }
 | |
| 
 | |
|   *Count = TemCount;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Generate random one range with randome attribute, and add it into pagetable
 | |
|   Compare the key point has same attribute
 | |
| 
 | |
|   @param[in, out] PageTable     The pointer to the page table to update, or pointer to NULL if a new page table is to be created.
 | |
|   @param[in]      PagingMode    The paging mode.
 | |
|   @param[in]      MaxAddress    Max Address.
 | |
|   @param[in]      MapEntrys     Record every memory ranges that is used as input
 | |
|   @param[in]      PagesRecord   Used to record memory usage for page table.
 | |
|   @param[in]      InitMap      Pointer to an array that describes init map entries.
 | |
|   @param[in]      InitMapCount Pointer to a UINTN that hold the number of init map entries.
 | |
| 
 | |
|   @retval  UNIT_TEST_PASSED        The test is successful.
 | |
| **/
 | |
| UNIT_TEST_STATUS
 | |
| SingleMapEntryTest (
 | |
|   IN OUT UINTN                  *PageTable,
 | |
|   IN     PAGING_MODE            PagingMode,
 | |
|   IN     UINT64                 MaxAddress,
 | |
|   IN     MAP_ENTRYS             *MapEntrys,
 | |
|   IN     ALLOCATE_PAGE_RECORDS  *PagesRecord,
 | |
|   IN     IA32_MAP_ENTRY         *InitMap,
 | |
|   IN     UINTN                  InitMapCount
 | |
|   )
 | |
| {
 | |
|   UINTN             MapsIndex;
 | |
|   RETURN_STATUS     Status;
 | |
|   UINTN             PageTableBufferSize;
 | |
|   VOID              *Buffer;
 | |
|   IA32_MAP_ENTRY    *Map;
 | |
|   UINTN             MapCount;
 | |
|   UINTN             Index;
 | |
|   UINTN             KeyPointCount;
 | |
|   UINTN             NewKeyPointCount;
 | |
|   UINT64            *KeyPointBuffer;
 | |
|   UINTN             Level;
 | |
|   UINT64            Value;
 | |
|   UNIT_TEST_STATUS  TestStatus;
 | |
| 
 | |
|   MapsIndex = MapEntrys->Count;
 | |
| 
 | |
|   GenerateSingleRandomMapEntry (MaxAddress, MapEntrys);
 | |
| 
 | |
|   PageTableBufferSize = 0;
 | |
|   Status              = PageTableMap (
 | |
|                           PageTable,
 | |
|                           PagingMode,
 | |
|                           NULL,
 | |
|                           &PageTableBufferSize,
 | |
|                           MapEntrys->Maps[MapsIndex].LinearAddress,
 | |
|                           MapEntrys->Maps[MapsIndex].Length,
 | |
|                           &MapEntrys->Maps[MapsIndex].Attribute,
 | |
|                           &MapEntrys->Maps[MapsIndex].Mask
 | |
|                           );
 | |
|   if (PageTableBufferSize != 0) {
 | |
|     UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
 | |
| 
 | |
|     //
 | |
|     // Allocate memory for Page table
 | |
|     // Note the memory is used in one complete Random test.
 | |
|     //
 | |
|     Buffer = PagesRecord->AllocatePagesForPageTable (PagesRecord, EFI_SIZE_TO_PAGES (PageTableBufferSize));
 | |
|     UT_ASSERT_NOT_EQUAL (Buffer, NULL);
 | |
|     Status = PageTableMap (
 | |
|                PageTable,
 | |
|                PagingMode,
 | |
|                Buffer,
 | |
|                &PageTableBufferSize,
 | |
|                MapEntrys->Maps[MapsIndex].LinearAddress,
 | |
|                MapEntrys->Maps[MapsIndex].Length,
 | |
|                &MapEntrys->Maps[MapsIndex].Attribute,
 | |
|                &MapEntrys->Maps[MapsIndex].Mask
 | |
|                );
 | |
|   }
 | |
| 
 | |
|   if (Status != RETURN_SUCCESS ) {
 | |
|     UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
 | |
|   }
 | |
| 
 | |
|   UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
 | |
|   TestStatus = IsPageTableValid (*PageTable, PagingMode);
 | |
|   if (TestStatus != UNIT_TEST_PASSED) {
 | |
|     return TestStatus;
 | |
|   }
 | |
| 
 | |
|   MapCount = 0;
 | |
|   Status   = PageTableParse (*PageTable, PagingMode, NULL, &MapCount);
 | |
|   if (MapCount != 0) {
 | |
|     UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
 | |
| 
 | |
|     //
 | |
|     // Allocate memory for Maps
 | |
|     // Note the memory is only used in this one Single MapEntry Test
 | |
|     //
 | |
|     Map = AllocatePages (EFI_SIZE_TO_PAGES (MapCount * sizeof (IA32_MAP_ENTRY)));
 | |
|     ASSERT (Map != NULL);
 | |
|     Status = PageTableParse (*PageTable, PagingMode, Map, &MapCount);
 | |
|   }
 | |
| 
 | |
|   UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
 | |
| 
 | |
|   //
 | |
|   // Allocate memory to record all key point
 | |
|   // Note the memory is only used in this one Single MapEntry Test
 | |
|   //
 | |
|   KeyPointCount = 0;
 | |
|   GetKeyPointList (MapEntrys, Map, MapCount, NULL, &KeyPointCount);
 | |
|   KeyPointBuffer = AllocatePages (EFI_SIZE_TO_PAGES (KeyPointCount * sizeof (UINT64)));
 | |
|   ASSERT (KeyPointBuffer != NULL);
 | |
|   NewKeyPointCount = 0;
 | |
|   GetKeyPointList (MapEntrys, Map, MapCount, KeyPointBuffer, &NewKeyPointCount);
 | |
| 
 | |
|   //
 | |
|   // Compare all key point's attribute
 | |
|   //
 | |
|   for (Index = 0; Index < NewKeyPointCount; Index++) {
 | |
|     if (!CompareEntrysforOnePoint (KeyPointBuffer[Index], MapEntrys, Map, MapCount, InitMap, InitMapCount)) {
 | |
|       DEBUG ((DEBUG_INFO, "Error happens at below key point\n"));
 | |
|       DEBUG ((DEBUG_INFO, "Index = %d KeyPointBuffer[Index] = 0x%lx\n", Index, KeyPointBuffer[Index]));
 | |
|       Value = GetEntryFromPageTable (*PageTable, PagingMode, KeyPointBuffer[Index], &Level);
 | |
|       DEBUG ((DEBUG_INFO, "From Page table, this key point is in level %d entry, with entry value is 0x%lx\n", Level, Value));
 | |
|       UT_ASSERT_TRUE (FALSE);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   FreePages (KeyPointBuffer, EFI_SIZE_TO_PAGES (KeyPointCount * sizeof (UINT64)));
 | |
|   if (MapCount != 0) {
 | |
|     FreePages (Map, EFI_SIZE_TO_PAGES (MapCount * sizeof (IA32_MAP_ENTRY)));
 | |
|   }
 | |
| 
 | |
|   return UNIT_TEST_PASSED;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Allocate page and record the information in PagesRecord
 | |
| 
 | |
|   @param[in]  PagesRecord   Point to a struct to record memory usage
 | |
|   @param[in]  Pages         Page count needed to allocate
 | |
| 
 | |
|   @return A pointer to the allocated buffer or NULL if allocation fails.
 | |
| **/
 | |
| VOID *
 | |
| EFIAPI
 | |
| RecordAllocatePages (
 | |
|   IN ALLOCATE_PAGE_RECORDS  *PagesRecord,
 | |
|   IN UINTN                  Pages
 | |
|   )
 | |
| {
 | |
|   VOID  *Buffer;
 | |
| 
 | |
|   Buffer = NULL;
 | |
|   if (PagesRecord->Count < PagesRecord->MaxCount) {
 | |
|     Buffer                                          = AllocatePages (Pages);
 | |
|     PagesRecord->Records[PagesRecord->Count].Buffer = Buffer;
 | |
|     PagesRecord->Records[PagesRecord->Count].Pages  = Pages;
 | |
|     PagesRecord->Count++;
 | |
|   }
 | |
| 
 | |
|   ASSERT (Buffer != NULL);
 | |
| 
 | |
|   return Buffer;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The function is a whole Random test, it will call SingleMapEntryTest for ExpctedEntryNumber times
 | |
| 
 | |
|   @param[in]  ExpctedEntryNumber   The count of random entry
 | |
|   @param[in]  PagingMode           The paging mode.
 | |
| 
 | |
|   @retval  UNIT_TEST_PASSED        The test is successful.
 | |
| **/
 | |
| UNIT_TEST_STATUS
 | |
| MultipleMapEntryTest (
 | |
|   IN UINTN        ExpctedEntryNumber,
 | |
|   IN PAGING_MODE  PagingMode
 | |
|   )
 | |
| {
 | |
|   UINTN                  PageTable;
 | |
|   UINT64                 MaxAddress;
 | |
|   MAP_ENTRYS             *MapEntrys;
 | |
|   ALLOCATE_PAGE_RECORDS  *PagesRecord;
 | |
|   UINTN                  Index;
 | |
|   UNIT_TEST_STATUS       TestStatus;
 | |
|   RETURN_STATUS          Status;
 | |
|   IA32_MAP_ENTRY         *InitMap;
 | |
|   UINTN                  InitMapCount;
 | |
| 
 | |
|   MaxAddress = GetMaxAddress (PagingMode);
 | |
|   PageTable  = 0;
 | |
|   MapEntrys  = AllocatePages (EFI_SIZE_TO_PAGES (1000*sizeof (MAP_ENTRY) + sizeof (MAP_ENTRYS)));
 | |
|   ASSERT (MapEntrys != NULL);
 | |
|   MapEntrys->Count     = 0;
 | |
|   MapEntrys->InitCount = 0;
 | |
|   MapEntrys->MaxCount  = 1000;
 | |
|   PagesRecord          = AllocatePages (EFI_SIZE_TO_PAGES (1000*sizeof (ALLOCATE_PAGE_RECORD) + sizeof (ALLOCATE_PAGE_RECORDS)));
 | |
|   ASSERT (PagesRecord != NULL);
 | |
|   PagesRecord->Count                     = 0;
 | |
|   PagesRecord->MaxCount                  = 1000;
 | |
|   PagesRecord->AllocatePagesForPageTable = RecordAllocatePages;
 | |
| 
 | |
|   if (mRandomOption & MANUAL_CHANGE_PAGE_TABLE) {
 | |
|     ExpctedEntryNumber = ExpctedEntryNumber/2;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < ExpctedEntryNumber; Index++) {
 | |
|     TestStatus = SingleMapEntryTest (
 | |
|                    &PageTable,
 | |
|                    PagingMode,
 | |
|                    MaxAddress,
 | |
|                    MapEntrys,
 | |
|                    PagesRecord,
 | |
|                    NULL,
 | |
|                    0
 | |
|                    );
 | |
|     if (TestStatus != UNIT_TEST_PASSED) {
 | |
|       return TestStatus;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ((mRandomOption & MANUAL_CHANGE_PAGE_TABLE) != 0) {
 | |
|     MapEntrys->InitCount = ExpctedEntryNumber;
 | |
|     TestStatus           = ValidateAndRandomeModifyPageTable (PageTable, PagingMode);
 | |
|     RandomNumber         = 0;
 | |
|     if (TestStatus != UNIT_TEST_PASSED) {
 | |
|       return TestStatus;
 | |
|     }
 | |
| 
 | |
|     InitMapCount = 0;
 | |
|     Status       = PageTableParse (PageTable, PagingMode, NULL, &InitMapCount);
 | |
|     if (InitMapCount != 0) {
 | |
|       UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
 | |
| 
 | |
|       //
 | |
|       // Allocate memory for Maps
 | |
|       // Note the memory is only used in this one Single MapEntry Test
 | |
|       //
 | |
|       InitMap = AllocatePages (EFI_SIZE_TO_PAGES (InitMapCount * sizeof (IA32_MAP_ENTRY)));
 | |
|       ASSERT (InitMap != NULL);
 | |
|       Status = PageTableParse (PageTable, PagingMode, InitMap, &InitMapCount);
 | |
|     }
 | |
| 
 | |
|     UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
 | |
|     for (Index = 0; Index < ExpctedEntryNumber; Index++) {
 | |
|       TestStatus = SingleMapEntryTest (
 | |
|                      &PageTable,
 | |
|                      PagingMode,
 | |
|                      MaxAddress,
 | |
|                      MapEntrys,
 | |
|                      PagesRecord,
 | |
|                      InitMap,
 | |
|                      InitMapCount
 | |
|                      );
 | |
|       if (TestStatus != UNIT_TEST_PASSED) {
 | |
|         return TestStatus;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (InitMapCount != 0) {
 | |
|       FreePages (InitMap, EFI_SIZE_TO_PAGES (InitMapCount*sizeof (IA32_MAP_ENTRY)));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   FreePages (
 | |
|     MapEntrys,
 | |
|     EFI_SIZE_TO_PAGES (1000*sizeof (MAP_ENTRY) + sizeof (MAP_ENTRYS))
 | |
|     );
 | |
| 
 | |
|   for (Index = 0; Index < PagesRecord->Count; Index++) {
 | |
|     FreePages (PagesRecord->Records[Index].Buffer, PagesRecord->Records[Index].Pages);
 | |
|   }
 | |
| 
 | |
|   FreePages (PagesRecord, EFI_SIZE_TO_PAGES (1000*sizeof (ALLOCATE_PAGE_RECORD) + sizeof (ALLOCATE_PAGE_RECORDS)));
 | |
| 
 | |
|   return UNIT_TEST_PASSED;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Random Test
 | |
| 
 | |
|   @param[in]  Context    [Optional] An optional parameter that enables:
 | |
|                          1) test-case reuse with varied parameters and
 | |
|                          2) test-case re-entry for Target tests that need a
 | |
|                          reboot.  This parameter is a VOID* and it is the
 | |
|                          responsibility of the test author to ensure that the
 | |
|                          contents are well understood by all test cases that may
 | |
|                          consume it.
 | |
| 
 | |
|   @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
 | |
| TestCaseforRandomTest (
 | |
|   IN UNIT_TEST_CONTEXT  Context
 | |
|   )
 | |
| {
 | |
|   UNIT_TEST_STATUS  Status;
 | |
|   UINTN             Index;
 | |
| 
 | |
|   UT_ASSERT_EQUAL (RandomSeed (NULL, 0), TRUE);
 | |
|   UT_ASSERT_EQUAL (Random32 (100, 100), 100);
 | |
|   UT_ASSERT_EQUAL (Random64 (100, 100), 100);
 | |
|   UT_ASSERT_TRUE ((Random32 (9, 10) >= 9) & (Random32 (9, 10) <= 10));
 | |
|   UT_ASSERT_TRUE ((Random64 (9, 10) >= 9) & (Random64 (9, 10) <= 10));
 | |
| 
 | |
|   mSupportedBit.Bits.Present              = 1;
 | |
|   mSupportedBit.Bits.ReadWrite            = 1;
 | |
|   mSupportedBit.Bits.UserSupervisor       = 1;
 | |
|   mSupportedBit.Bits.WriteThrough         = 1;
 | |
|   mSupportedBit.Bits.CacheDisabled        = 1;
 | |
|   mSupportedBit.Bits.Accessed             = 1;
 | |
|   mSupportedBit.Bits.Dirty                = 1;
 | |
|   mSupportedBit.Bits.Pat                  = 1;
 | |
|   mSupportedBit.Bits.Global               = 1;
 | |
|   mSupportedBit.Bits.Reserved1            = 0;
 | |
|   mSupportedBit.Bits.PageTableBaseAddress = 0;
 | |
|   mSupportedBit.Bits.Reserved2            = 0;
 | |
|   mSupportedBit.Bits.ProtectionKey        = 0xF;
 | |
|   mSupportedBit.Bits.Nx                   = 1;
 | |
| 
 | |
|   mRandomOption = ((CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT *)Context)->RandomOption;
 | |
|   mNumberIndex  = 0;
 | |
| 
 | |
|   for (Index = 0; Index < ((CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT *)Context)->TestCount; Index++) {
 | |
|     Status = MultipleMapEntryTest (
 | |
|                ((CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT *)Context)->TestRangeCount,
 | |
|                ((CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT *)Context)->PagingMode
 | |
|                );
 | |
|     if (Status != UNIT_TEST_PASSED) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     DEBUG ((DEBUG_INFO, "."));
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_INFO, "\n"));
 | |
| 
 | |
|   return UNIT_TEST_PASSED;
 | |
| }
 |