mirror of https://github.com/acidanthera/audk.git
1063 lines
37 KiB
C
1063 lines
37 KiB
C
/** @file
|
|
Random test case for Unit tests of the CpuPageTableLib instance of the CpuPageTableLib class
|
|
|
|
Copyright (c) 2022 - 2023, 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 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;
|
|
}
|
|
|
|
/**
|
|
Returns true with the percentage of input Probability.
|
|
|
|
@param[in] Probability The percentage to return true.
|
|
|
|
@return boolean
|
|
**/
|
|
BOOLEAN
|
|
RandomBoolean (
|
|
UINT8 Probability
|
|
)
|
|
{
|
|
return ((Probability > ((UINT8)Random64 (0, 100))) ? TRUE : FALSE);
|
|
}
|
|
|
|
/**
|
|
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;
|
|
UINT32 PageTableBaseAddressLow;
|
|
UINT32 PageTableBaseAddressHigh;
|
|
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 (50)) {
|
|
RandomNumber++;
|
|
if (Level == 1) {
|
|
PageTableBaseAddressLow = PagingEntry->Pte4K.Bits.PageTableBaseAddressLow;
|
|
PageTableBaseAddressHigh = PagingEntry->Pte4K.Bits.PageTableBaseAddressHigh;
|
|
} else {
|
|
PageTableBaseAddressLow = PagingEntry->PleB.Bits.PageTableBaseAddressLow;
|
|
PageTableBaseAddressHigh = PagingEntry->PleB.Bits.PageTableBaseAddressHigh;
|
|
}
|
|
|
|
PagingEntry->Uint64 = (Random64 (0, MAX_UINT64) & mValidMaskLeaf[Level].Uint64) | mValidMaskLeafFlag[Level].Uint64;
|
|
PagingEntry->Pte4K.Bits.Present = 1;
|
|
if (Level == 1) {
|
|
PagingEntry->Pte4K.Bits.PageTableBaseAddressLow = PageTableBaseAddressLow;
|
|
PagingEntry->Pte4K.Bits.PageTableBaseAddressHigh = PageTableBaseAddressHigh;
|
|
} else {
|
|
PagingEntry->PleB.Bits.PageTableBaseAddressLow = PageTableBaseAddressLow;
|
|
PagingEntry->PleB.Bits.PageTableBaseAddressHigh = PageTableBaseAddressHigh;
|
|
}
|
|
|
|
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 (50)) {
|
|
RandomNumber++;
|
|
PageTableBaseAddressLow = PagingEntry->PleB.Bits.PageTableBaseAddressLow;
|
|
PageTableBaseAddressHigh = PagingEntry->PleB.Bits.PageTableBaseAddressHigh;
|
|
|
|
PagingEntry->Uint64 = Random64 (0, MAX_UINT64) & mValidMaskNoLeaf[Level].Uint64;
|
|
PagingEntry->Pnle.Bits.Present = 1;
|
|
PagingEntry->PleB.Bits.PageTableBaseAddressLow = PageTableBaseAddressLow;
|
|
PagingEntry->PleB.Bits.PageTableBaseAddressHigh = PageTableBaseAddressHigh;
|
|
ASSERT ((PagingEntry->Uint64 & mValidMaskLeafFlag[Level].Uint64) != mValidMaskLeafFlag[Level].Uint64);
|
|
}
|
|
|
|
ChildPageEntry = (IA32_PAGING_ENTRY *)(UINTN)(IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&PagingEntry->Pnle));
|
|
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 >= PagingModeMax)) {
|
|
//
|
|
// 32bit paging is never supported.
|
|
//
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Remove the last MAP_ENTRY in MapEntrys.
|
|
|
|
@param MapEntrys Pointer to MapEntrys buffer
|
|
**/
|
|
VOID
|
|
RemoveLastMapEntry (
|
|
IN OUT MAP_ENTRYS *MapEntrys
|
|
)
|
|
{
|
|
UINTN MapsIndex;
|
|
|
|
if (MapEntrys->Count == 0) {
|
|
return;
|
|
}
|
|
|
|
MapsIndex = MapEntrys->Count - 1;
|
|
ZeroMem (&(MapEntrys->Maps[MapsIndex]), sizeof (MAP_ENTRY));
|
|
MapEntrys->Count = MapsIndex;
|
|
}
|
|
|
|
/**
|
|
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 (50))) {
|
|
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 (50))) {
|
|
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;
|
|
if (RandomBoolean (5)) {
|
|
//
|
|
// The probability to get random Mask should be small since all bits of a random number
|
|
// have a high probability of containing 0, which may be a invalid input.
|
|
//
|
|
MapEntrys->Maps[MapsIndex].Mask.Uint64 = Random64 (0, MAX_UINT64) & mSupportedBit.Uint64;
|
|
} else {
|
|
MapEntrys->Maps[MapsIndex].Mask.Uint64 = MAX_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.Uint64 &= (~IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS_MASK);
|
|
MapEntrys->Maps[MapsIndex].Attribute.Uint64 |= MapEntrys->Maps[MapsIndex].LinearAddress;
|
|
MapEntrys->Maps[MapsIndex].Mask.Uint64 |= IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS_MASK;
|
|
} else {
|
|
MapEntrys->Maps[MapsIndex].Attribute.Uint64 &= (~IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS_MASK);
|
|
MapEntrys->Maps[MapsIndex].Attribute.Uint64 |= (Random64 (0, (((UINT64)1)<<52) - 1) & AlignedTable[Random32 (0, ARRAY_SIZE (AlignedTable) -1)]);
|
|
}
|
|
|
|
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.Uint64 &= (~IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS_MASK);
|
|
AttributeInMap.Uint64 |= (Address - Map[Index].LinearAddress + IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (&Map[Index].Attribute)) & IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS_MASK;
|
|
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.Uint64 &= (~IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS_MASK);
|
|
AttributeInInitMap.Uint64 |= (Address - InitMap[Index].LinearAddress + IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (&InitMap[Index].Attribute)) & IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS_MASK;
|
|
|
|
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 (IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (&MapEntrys->Maps[Index].Mask) != 0) {
|
|
AttributeInMapEntrys.Uint64 &= (~IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS_MASK);
|
|
AttributeInMapEntrys.Uint64 |= (Address - MapEntrys->Maps[Index].LinearAddress + IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (&MapEntrys->Maps[Index].Attribute)) & IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS_MASK;
|
|
}
|
|
}
|
|
}
|
|
|
|
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, IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (&AttributeInMap)));
|
|
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, IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (&AttributeInMapEntrys)));
|
|
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;
|
|
IA32_MAP_ENTRY *Map2;
|
|
UINTN MapCount2;
|
|
UINTN Index;
|
|
UINTN KeyPointCount;
|
|
UINTN NewKeyPointCount;
|
|
UINT64 *KeyPointBuffer;
|
|
UINTN Level;
|
|
UINT64 Value;
|
|
UNIT_TEST_STATUS TestStatus;
|
|
MAP_ENTRY *LastMapEntry;
|
|
IA32_MAP_ATTRIBUTE *Mask;
|
|
IA32_MAP_ATTRIBUTE *Attribute;
|
|
UINT64 LastNotPresentRegionStart;
|
|
BOOLEAN IsNotPresent;
|
|
BOOLEAN IsModified;
|
|
|
|
MapsIndex = MapEntrys->Count;
|
|
MapCount = 0;
|
|
LastNotPresentRegionStart = 0;
|
|
IsNotPresent = FALSE;
|
|
IsModified = FALSE;
|
|
|
|
GenerateSingleRandomMapEntry (MaxAddress, MapEntrys);
|
|
LastMapEntry = &MapEntrys->Maps[MapsIndex];
|
|
Status = PageTableParse (*PageTable, PagingMode, NULL, &MapCount);
|
|
|
|
if (MapCount != 0) {
|
|
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
|
Map = AllocatePages (EFI_SIZE_TO_PAGES (MapCount * sizeof (IA32_MAP_ENTRY)));
|
|
ASSERT (Map != NULL);
|
|
Status = PageTableParse (*PageTable, PagingMode, Map, &MapCount);
|
|
}
|
|
|
|
//
|
|
// Check if the generated MapEntrys->Maps[MapsIndex] contains not-present range.
|
|
//
|
|
if (LastMapEntry->Length > 0) {
|
|
for (Index = 0; Index < MapCount; Index++) {
|
|
if ((LastNotPresentRegionStart < Map[Index].LinearAddress) &&
|
|
(LastMapEntry->LinearAddress < Map[Index].LinearAddress) && (LastMapEntry->LinearAddress + LastMapEntry->Length > LastNotPresentRegionStart))
|
|
{
|
|
//
|
|
// MapEntrys->Maps[MapsIndex] contains not-present range in exsiting page table.
|
|
//
|
|
break;
|
|
}
|
|
|
|
LastNotPresentRegionStart = Map[Index].LinearAddress + Map[Index].Length;
|
|
}
|
|
|
|
//
|
|
// Either LastMapEntry overlaps with the not-present region in the very end
|
|
// Or it overlaps with one in the middle
|
|
if (LastNotPresentRegionStart < LastMapEntry->LinearAddress + LastMapEntry->Length) {
|
|
IsNotPresent = TRUE;
|
|
}
|
|
}
|
|
|
|
PageTableBufferSize = 0;
|
|
Status = PageTableMap (
|
|
PageTable,
|
|
PagingMode,
|
|
NULL,
|
|
&PageTableBufferSize,
|
|
LastMapEntry->LinearAddress,
|
|
LastMapEntry->Length,
|
|
&LastMapEntry->Attribute,
|
|
&LastMapEntry->Mask,
|
|
&IsModified
|
|
);
|
|
|
|
Attribute = &LastMapEntry->Attribute;
|
|
Mask = &LastMapEntry->Mask;
|
|
//
|
|
// If set [LinearAddress, LinearAddress+Attribute] to not preset, all
|
|
// other attributes should not be provided.
|
|
//
|
|
if ((LastMapEntry->Length > 0) && (Attribute->Bits.Present == 0) && (Mask->Bits.Present == 1) && (Mask->Uint64 > 1)) {
|
|
RemoveLastMapEntry (MapEntrys);
|
|
UT_ASSERT_EQUAL (Status, RETURN_INVALID_PARAMETER);
|
|
return UNIT_TEST_PASSED;
|
|
}
|
|
|
|
//
|
|
// Return Status for non-present range also should be InvalidParameter when:
|
|
// 1. Some of attributes are not provided when mapping non-present range to present.
|
|
// 2. Set any other attribute without setting the non-present range to Present.
|
|
//
|
|
if (IsNotPresent) {
|
|
if ((Mask->Bits.Present == 1) && (Attribute->Bits.Present == 1)) {
|
|
//
|
|
// Creating new page table or remapping non-present range to present.
|
|
//
|
|
if ((Mask->Bits.ReadWrite == 0) || (Mask->Bits.UserSupervisor == 0) || (Mask->Bits.WriteThrough == 0) || (Mask->Bits.CacheDisabled == 0) ||
|
|
(Mask->Bits.Accessed == 0) || (Mask->Bits.Dirty == 0) || (Mask->Bits.Pat == 0) || (Mask->Bits.Global == 0) ||
|
|
((Mask->Bits.PageTableBaseAddressLow == 0) && (Mask->Bits.PageTableBaseAddressHigh == 0)) || (Mask->Bits.ProtectionKey == 0) || (Mask->Bits.Nx == 0))
|
|
{
|
|
RemoveLastMapEntry (MapEntrys);
|
|
UT_ASSERT_EQUAL (Status, RETURN_INVALID_PARAMETER);
|
|
return UNIT_TEST_PASSED;
|
|
}
|
|
} else if ((Mask->Bits.Present == 0) && (Mask->Uint64 > 1)) {
|
|
//
|
|
// Only change other attributes for non-present range is not permitted.
|
|
//
|
|
RemoveLastMapEntry (MapEntrys);
|
|
UT_ASSERT_EQUAL (Status, RETURN_INVALID_PARAMETER);
|
|
return UNIT_TEST_PASSED;
|
|
}
|
|
}
|
|
|
|
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,
|
|
LastMapEntry->LinearAddress,
|
|
LastMapEntry->Length,
|
|
&LastMapEntry->Attribute,
|
|
&LastMapEntry->Mask,
|
|
&IsModified
|
|
);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
MapCount2 = 0;
|
|
Status = PageTableParse (*PageTable, PagingMode, NULL, &MapCount2);
|
|
if (MapCount2 != 0) {
|
|
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
|
|
|
//
|
|
// Allocate memory for Map2
|
|
// Note the memory is only used in this one Single MapEntry Test
|
|
//
|
|
Map2 = AllocatePages (EFI_SIZE_TO_PAGES (MapCount2 * sizeof (IA32_MAP_ENTRY)));
|
|
ASSERT (Map2 != NULL);
|
|
Status = PageTableParse (*PageTable, PagingMode, Map2, &MapCount2);
|
|
}
|
|
|
|
//
|
|
// Check if PageTable has been modified.
|
|
//
|
|
if (MapCount2 != MapCount) {
|
|
UT_ASSERT_EQUAL (IsModified, TRUE);
|
|
} else {
|
|
if (CompareMem (Map, Map2, MapCount2 * sizeof (IA32_MAP_ENTRY)) != 0) {
|
|
UT_ASSERT_EQUAL (IsModified, TRUE);
|
|
} else {
|
|
UT_ASSERT_EQUAL (IsModified, FALSE);
|
|
}
|
|
}
|
|
|
|
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, Map2, MapCount2, NULL, &KeyPointCount);
|
|
KeyPointBuffer = AllocatePages (EFI_SIZE_TO_PAGES (KeyPointCount * sizeof (UINT64)));
|
|
ASSERT (KeyPointBuffer != NULL);
|
|
NewKeyPointCount = 0;
|
|
GetKeyPointList (MapEntrys, Map2, MapCount2, KeyPointBuffer, &NewKeyPointCount);
|
|
|
|
//
|
|
// Compare all key point's attribute
|
|
//
|
|
for (Index = 0; Index < NewKeyPointCount; Index++) {
|
|
if (!CompareEntrysforOnePoint (KeyPointBuffer[Index], MapEntrys, Map2, MapCount2, 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)));
|
|
}
|
|
|
|
if (MapCount2 != 0) {
|
|
FreePages (Map2, EFI_SIZE_TO_PAGES (MapCount2 * 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.Uint64 = 0;
|
|
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.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;
|
|
}
|