mirror of https://github.com/acidanthera/audk.git
Revert "UefiCpuPkg/CpuPageTableLib/UnitTest: Add host based unit test"
This reverts commit 2812668bfc
for tag202208.
This feature will be merged after stable tag 202208 is created.
Signed-off-by: Liming Gao <gaoliming@byosoft.com.cn>
Reviewed-by: Zhiguang Liu <zhiguang.liu@intel.com>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
parent
0ede7cad73
commit
722e03bc2e
|
@ -1,117 +0,0 @@
|
|||
/** @file
|
||||
|
||||
Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef CPU_PAGE_TABLE_SUPPORT_H_
|
||||
#define CPU_PAGE_TABLE_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/CpuPageTableLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UnitTestHostBaseLib.h>
|
||||
#include <Library/BaseCryptLib.h>
|
||||
#include "../CpuPageTable.h"
|
||||
|
||||
#define UNIT_TEST_APP_NAME "Cpu Page Table Lib Unit Tests"
|
||||
#define UNIT_TEST_APP_VERSION "1.0"
|
||||
|
||||
//
|
||||
// Random Options
|
||||
//
|
||||
|
||||
//
|
||||
// Only test one-one mapping case
|
||||
//
|
||||
#define ONLY_ONE_ONE_MAPPING 0x00000001
|
||||
|
||||
//
|
||||
// Change page table without using function PageTableMap, and use the modified page table as input
|
||||
//
|
||||
#define MANUAL_CHANGE_PAGE_TABLE 0x00000002
|
||||
|
||||
//
|
||||
// Use pre-generated random number array to generate random number
|
||||
//
|
||||
#define USE_RANDOM_ARRAY 0x00000004
|
||||
|
||||
typedef struct {
|
||||
PAGING_MODE PagingMode;
|
||||
UINTN TestCount;
|
||||
UINTN TestRangeCount;
|
||||
UINTN RandomOption;
|
||||
} CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT;
|
||||
|
||||
/**
|
||||
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
|
||||
);
|
||||
|
||||
/**
|
||||
Init global data
|
||||
|
||||
@param[in] MemorySpace Memory space
|
||||
**/
|
||||
VOID
|
||||
InitGlobalData (
|
||||
UINTN MemorySpace
|
||||
);
|
||||
|
||||
/**
|
||||
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
|
||||
IsPageTableValid (
|
||||
IN UINTN PageTable,
|
||||
IN PAGING_MODE PagingMode
|
||||
);
|
||||
|
||||
/**
|
||||
Get max physical adrress supported by specific page mode
|
||||
|
||||
@param[in] Mode The paging mode.
|
||||
|
||||
@retval max address.
|
||||
**/
|
||||
UINT64
|
||||
GetMaxAddress (
|
||||
IN PAGING_MODE Mode
|
||||
);
|
||||
|
||||
#endif
|
|
@ -1,794 +0,0 @@
|
|||
/** @file
|
||||
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"
|
||||
|
||||
// ----------------------------------------------------------------------- PageMode--TestCount-TestRangeCount---RandomOptions
|
||||
static CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT mTestContextPaging4Level = { Paging4Level, 100, 20, ONLY_ONE_ONE_MAPPING|USE_RANDOM_ARRAY };
|
||||
static CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT mTestContextPaging4Level1GB = { Paging4Level1GB, 100, 20, ONLY_ONE_ONE_MAPPING|USE_RANDOM_ARRAY };
|
||||
static CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT mTestContextPaging5Level = { Paging5Level, 100, 20, ONLY_ONE_ONE_MAPPING|USE_RANDOM_ARRAY };
|
||||
static CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT mTestContextPaging5Level1GB = { Paging5Level1GB, 100, 20, ONLY_ONE_ONE_MAPPING|USE_RANDOM_ARRAY };
|
||||
|
||||
/**
|
||||
Check if the input parameters are not supported.
|
||||
|
||||
@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
|
||||
TestCaseForParameter (
|
||||
IN UNIT_TEST_CONTEXT Context
|
||||
)
|
||||
{
|
||||
UINTN PageTable;
|
||||
PAGING_MODE PagingMode;
|
||||
UINTN Buffer;
|
||||
UINTN PageTableBufferSize;
|
||||
IA32_MAP_ATTRIBUTE MapAttribute;
|
||||
IA32_MAP_ATTRIBUTE MapMask;
|
||||
|
||||
MapAttribute.Uint64 = 0;
|
||||
MapMask.Uint64 = 0;
|
||||
PagingMode = Paging5Level1GB;
|
||||
PageTableBufferSize = 0;
|
||||
PageTable = 0;
|
||||
|
||||
//
|
||||
// If the input linear address is not 4K align, it should return invalid parameter
|
||||
//
|
||||
UT_ASSERT_EQUAL (PageTableMap (&PageTable, PagingMode, &Buffer, &PageTableBufferSize, 1, SIZE_4KB, &MapAttribute, &MapMask), RETURN_INVALID_PARAMETER);
|
||||
|
||||
//
|
||||
// If the input PageTableBufferSize is not 4K align, it should return invalid parameter
|
||||
//
|
||||
PageTableBufferSize = 10;
|
||||
UT_ASSERT_EQUAL (PageTableMap (&PageTable, PagingMode, &Buffer, &PageTableBufferSize, 0, SIZE_4KB, &MapAttribute, &MapMask), RETURN_INVALID_PARAMETER);
|
||||
|
||||
//
|
||||
// If the input PagingMode is Paging32bit, it should return invalid parameter
|
||||
//
|
||||
PageTableBufferSize = 0;
|
||||
PagingMode = Paging32bit;
|
||||
UT_ASSERT_EQUAL (PageTableMap (&PageTable, PagingMode, &Buffer, &PageTableBufferSize, 1, SIZE_4KB, &MapAttribute, &MapMask), RETURN_UNSUPPORTED);
|
||||
|
||||
//
|
||||
// If the input MapMask is NULL, it should return invalid parameter
|
||||
//
|
||||
PagingMode = Paging5Level1GB;
|
||||
UT_ASSERT_EQUAL (PageTableMap (&PageTable, PagingMode, &Buffer, &PageTableBufferSize, 1, SIZE_4KB, &MapAttribute, NULL), RETURN_INVALID_PARAMETER);
|
||||
|
||||
return UNIT_TEST_PASSED;
|
||||
}
|
||||
|
||||
/**
|
||||
Check the case that modifying page table doesn't need extra buffe
|
||||
|
||||
@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
|
||||
TestCaseWhichNoNeedExtraSize (
|
||||
IN UNIT_TEST_CONTEXT Context
|
||||
)
|
||||
{
|
||||
UINTN PageTable;
|
||||
PAGING_MODE PagingMode;
|
||||
VOID *Buffer;
|
||||
UINTN PageTableBufferSize;
|
||||
IA32_MAP_ATTRIBUTE MapAttribute;
|
||||
IA32_MAP_ATTRIBUTE MapMask;
|
||||
RETURN_STATUS Status;
|
||||
UNIT_TEST_STATUS TestStatus;
|
||||
|
||||
MapAttribute.Uint64 = 0;
|
||||
MapMask.Uint64 = 0;
|
||||
PagingMode = Paging4Level1GB;
|
||||
PageTableBufferSize = 0;
|
||||
PageTable = 0;
|
||||
Buffer = NULL;
|
||||
MapAttribute.Bits.Present = 1;
|
||||
MapAttribute.Bits.Nx = 1;
|
||||
MapMask.Bits.Present = 1;
|
||||
MapMask.Uint64 = MAX_UINT64;
|
||||
|
||||
//
|
||||
// Create page table to cover [0, 10M], it should have 5 PTE
|
||||
//
|
||||
Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, 0, (UINT64)SIZE_2MB * 5, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
Buffer = AllocatePages (EFI_SIZE_TO_PAGES (PageTableBufferSize));
|
||||
Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, 0, (UINT64)SIZE_2MB * 5, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
TestStatus = IsPageTableValid (PageTable, PagingMode);
|
||||
if (TestStatus != UNIT_TEST_PASSED) {
|
||||
return TestStatus;
|
||||
}
|
||||
|
||||
//
|
||||
// call library to cover [0, 4K], because the page table is already cover [0, 10M], and no attribute change,
|
||||
// We assume the fucntion doesn't need to change page table, return success and output BufferSize is 0
|
||||
//
|
||||
Buffer = NULL;
|
||||
Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, 0, (UINT64)SIZE_4KB, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (PageTableBufferSize, 0);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
TestStatus = IsPageTableValid (PageTable, PagingMode);
|
||||
if (TestStatus != UNIT_TEST_PASSED) {
|
||||
return TestStatus;
|
||||
}
|
||||
|
||||
//
|
||||
// Same range and same attribute, only clear one mask attribute bit
|
||||
// We assume the fucntion doesn't need to change page table, return success and output BufferSize is 0
|
||||
//
|
||||
MapMask.Bits.Nx = 0;
|
||||
PageTableBufferSize = 0;
|
||||
Status = PageTableMap (&PageTable, PagingMode, NULL, &PageTableBufferSize, 0, (UINT64)SIZE_4KB, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
UT_ASSERT_EQUAL (PageTableBufferSize, 0);
|
||||
TestStatus = IsPageTableValid (PageTable, PagingMode);
|
||||
if (TestStatus != UNIT_TEST_PASSED) {
|
||||
return TestStatus;
|
||||
}
|
||||
|
||||
//
|
||||
// call library to cover [2M, 4M], while the page table is already cover [0, 10M],
|
||||
// only change one attribute bit, we assume the page table change be modified even if the
|
||||
// input Buffer is NULL, and BufferSize is 0
|
||||
//
|
||||
MapAttribute.Bits.Accessed = 1;
|
||||
MapMask.Bits.Accessed = 1;
|
||||
PageTableBufferSize = 0;
|
||||
Status = PageTableMap (&PageTable, PagingMode, NULL, &PageTableBufferSize, (UINT64)SIZE_2MB, (UINT64)SIZE_2MB, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
UT_ASSERT_EQUAL (PageTableBufferSize, 0);
|
||||
TestStatus = IsPageTableValid (PageTable, PagingMode);
|
||||
if (TestStatus != UNIT_TEST_PASSED) {
|
||||
return TestStatus;
|
||||
}
|
||||
|
||||
return UNIT_TEST_PASSED;
|
||||
}
|
||||
|
||||
/**
|
||||
Test Case that check the case to map [0, 1G] to [8K, 1G+8K]
|
||||
|
||||
@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
|
||||
TestCase1Gmapto4K (
|
||||
IN UNIT_TEST_CONTEXT Context
|
||||
)
|
||||
{
|
||||
UINTN PageTable;
|
||||
PAGING_MODE PagingMode;
|
||||
VOID *Buffer;
|
||||
UINTN PageTableBufferSize;
|
||||
IA32_MAP_ATTRIBUTE MapAttribute;
|
||||
IA32_MAP_ATTRIBUTE MapMask;
|
||||
RETURN_STATUS Status;
|
||||
UNIT_TEST_STATUS TestStatus;
|
||||
|
||||
//
|
||||
// Create Page table to map [0,1G] to [8K, 1G+8K]
|
||||
//
|
||||
PagingMode = Paging4Level1GB;
|
||||
PageTableBufferSize = 0;
|
||||
PageTable = 0;
|
||||
Buffer = NULL;
|
||||
MapAttribute.Uint64 = (UINT64)SIZE_4KB * 2;
|
||||
MapMask.Uint64 = (UINT64)SIZE_4KB * 2;
|
||||
MapAttribute.Bits.Present = 1;
|
||||
MapMask.Bits.Present = 1;
|
||||
MapMask.Uint64 = MAX_UINT64;
|
||||
Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, (UINT64)0, (UINT64)SIZE_1GB, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
Buffer = AllocatePages (EFI_SIZE_TO_PAGES (PageTableBufferSize));
|
||||
Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, (UINT64)0, (UINT64)SIZE_1GB, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
|
||||
//
|
||||
// Page table should be valid. (All reserved bits are zero)
|
||||
//
|
||||
TestStatus = IsPageTableValid (PageTable, PagingMode);
|
||||
if (TestStatus != UNIT_TEST_PASSED) {
|
||||
return TestStatus;
|
||||
}
|
||||
|
||||
return UNIT_TEST_PASSED;
|
||||
}
|
||||
|
||||
/**
|
||||
Check if the parent entry has different R/W attribute
|
||||
|
||||
@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
|
||||
TestCaseManualChangeReadWrite (
|
||||
IN UNIT_TEST_CONTEXT Context
|
||||
)
|
||||
{
|
||||
UINTN PageTable;
|
||||
PAGING_MODE PagingMode;
|
||||
VOID *Buffer;
|
||||
UINTN PageTableBufferSize;
|
||||
IA32_MAP_ATTRIBUTE MapAttribute;
|
||||
IA32_MAP_ATTRIBUTE ExpectedMapAttribute;
|
||||
IA32_MAP_ATTRIBUTE MapMask;
|
||||
RETURN_STATUS Status;
|
||||
IA32_MAP_ENTRY *Map;
|
||||
UINTN MapCount;
|
||||
IA32_PAGING_ENTRY *PagingEntry;
|
||||
VOID *BackupBuffer;
|
||||
UINTN BackupPageTableBufferSize;
|
||||
|
||||
PagingMode = Paging4Level;
|
||||
PageTableBufferSize = 0;
|
||||
PageTable = 0;
|
||||
Buffer = NULL;
|
||||
MapAttribute.Uint64 = 0;
|
||||
MapMask.Uint64 = MAX_UINT64;
|
||||
MapAttribute.Bits.Present = 1;
|
||||
MapAttribute.Bits.ReadWrite = 1;
|
||||
|
||||
//
|
||||
// Create Page table to cover [0,2G], with ReadWrite = 1
|
||||
//
|
||||
Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, 0, SIZE_2GB, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
BackupPageTableBufferSize = PageTableBufferSize;
|
||||
Buffer = AllocatePages (EFI_SIZE_TO_PAGES (PageTableBufferSize));
|
||||
Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, 0, SIZE_2GB, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
IsPageTableValid (PageTable, PagingMode);
|
||||
|
||||
MapCount = 0;
|
||||
Status = PageTableParse (PageTable, PagingMode, NULL, &MapCount);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
IsPageTableValid (PageTable, PagingMode);
|
||||
Map = AllocatePages (EFI_SIZE_TO_PAGES (MapCount));
|
||||
Status = PageTableParse (PageTable, PagingMode, Map, &MapCount);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
UT_ASSERT_EQUAL (MapCount, 1);
|
||||
UT_ASSERT_EQUAL (Map[0].LinearAddress, 0);
|
||||
UT_ASSERT_EQUAL (Map[0].Length, SIZE_2GB);
|
||||
ExpectedMapAttribute.Uint64 = MapAttribute.Uint64;
|
||||
UT_ASSERT_EQUAL (Map[0].Attribute.Uint64, ExpectedMapAttribute.Uint64);
|
||||
|
||||
//
|
||||
// Manually change ReadWrite to 0 for non-leaf entry, which covers [0,2G]
|
||||
//
|
||||
PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTable;
|
||||
PagingEntry->Uint64 = PagingEntry->Uint64 & (~(UINT64)0x2);
|
||||
MapCount = 0;
|
||||
Status = PageTableParse (PageTable, PagingMode, NULL, &MapCount);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
Map = AllocatePages (EFI_SIZE_TO_PAGES (MapCount));
|
||||
Status = PageTableParse (PageTable, PagingMode, Map, &MapCount);
|
||||
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
UT_ASSERT_EQUAL (MapCount, 1);
|
||||
UT_ASSERT_EQUAL (Map[0].LinearAddress, 0);
|
||||
UT_ASSERT_EQUAL (Map[0].Length, SIZE_2GB);
|
||||
ExpectedMapAttribute.Uint64 = MapAttribute.Uint64;
|
||||
ExpectedMapAttribute.Bits.ReadWrite = 0;
|
||||
UT_ASSERT_EQUAL (Map[0].Attribute.Uint64, ExpectedMapAttribute.Uint64);
|
||||
|
||||
//
|
||||
// Copy the page entry structure memory for future compare
|
||||
//
|
||||
BackupBuffer = AllocateCopyPool (BackupPageTableBufferSize, Buffer);
|
||||
UT_ASSERT_MEM_EQUAL (Buffer, BackupBuffer, BackupPageTableBufferSize);
|
||||
|
||||
//
|
||||
// Call library to change ReadWrite to 0 for [0,2M]
|
||||
//
|
||||
MapAttribute.Bits.ReadWrite = 0;
|
||||
Status = PageTableMap (&PageTable, PagingMode, NULL, &PageTableBufferSize, 0, SIZE_2MB, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
IsPageTableValid (PageTable, PagingMode);
|
||||
MapCount = 0;
|
||||
Status = PageTableParse (PageTable, PagingMode, NULL, &MapCount);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
Map = AllocatePages (EFI_SIZE_TO_PAGES (MapCount));
|
||||
Status = PageTableParse (PageTable, PagingMode, Map, &MapCount);
|
||||
//
|
||||
// There should be 1 range [0, 2G] with ReadWrite = 0
|
||||
//
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
UT_ASSERT_EQUAL (MapCount, 1);
|
||||
UT_ASSERT_EQUAL (Map[0].LinearAddress, 0);
|
||||
UT_ASSERT_EQUAL (Map[0].Length, SIZE_2GB);
|
||||
ExpectedMapAttribute.Uint64 = MapAttribute.Uint64;
|
||||
UT_ASSERT_EQUAL (Map[0].Attribute.Uint64, ExpectedMapAttribute.Uint64);
|
||||
|
||||
//
|
||||
// The latest PageTableMap call should change nothing.
|
||||
// The memory should be identical before and after the funtion is called.
|
||||
//
|
||||
UT_ASSERT_MEM_EQUAL (Buffer, BackupBuffer, BackupPageTableBufferSize);
|
||||
|
||||
//
|
||||
// Call library to change ReadWrite to 1 for [0, 2M]
|
||||
//
|
||||
MapAttribute.Bits.ReadWrite = 1;
|
||||
PageTableBufferSize = 0;
|
||||
Status = PageTableMap (&PageTable, PagingMode, NULL, &PageTableBufferSize, 0, SIZE_2MB, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
IsPageTableValid (PageTable, PagingMode);
|
||||
MapCount = 0;
|
||||
Status = PageTableParse (PageTable, PagingMode, NULL, &MapCount);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
Map = AllocatePages (EFI_SIZE_TO_PAGES (MapCount));
|
||||
Status = PageTableParse (PageTable, PagingMode, Map, &MapCount);
|
||||
//
|
||||
// There should be 2 range [0, 2M] with ReadWrite = 1 and [2M, 2G] with ReadWrite = 0
|
||||
//
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
UT_ASSERT_EQUAL (MapCount, 2);
|
||||
|
||||
UT_ASSERT_EQUAL (Map[0].LinearAddress, 0);
|
||||
UT_ASSERT_EQUAL (Map[0].Length, SIZE_2MB);
|
||||
ExpectedMapAttribute.Uint64 = MapAttribute.Uint64;
|
||||
UT_ASSERT_EQUAL (Map[0].Attribute.Uint64, ExpectedMapAttribute.Uint64);
|
||||
|
||||
UT_ASSERT_EQUAL (Map[1].LinearAddress, SIZE_2MB);
|
||||
UT_ASSERT_EQUAL (Map[1].Length, SIZE_2GB - SIZE_2MB);
|
||||
ExpectedMapAttribute.Uint64 = SIZE_2MB;
|
||||
ExpectedMapAttribute.Bits.ReadWrite = 0;
|
||||
ExpectedMapAttribute.Bits.Present = 1;
|
||||
UT_ASSERT_EQUAL (Map[1].Attribute.Uint64, ExpectedMapAttribute.Uint64);
|
||||
|
||||
return UNIT_TEST_PASSED;
|
||||
}
|
||||
|
||||
/**
|
||||
Check if the needed size is expected
|
||||
|
||||
@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
|
||||
TestCaseManualSizeNotMatch (
|
||||
IN UNIT_TEST_CONTEXT Context
|
||||
)
|
||||
{
|
||||
UINTN PageTable;
|
||||
PAGING_MODE PagingMode;
|
||||
VOID *Buffer;
|
||||
UINTN PageTableBufferSize;
|
||||
IA32_MAP_ATTRIBUTE MapAttribute;
|
||||
IA32_MAP_ATTRIBUTE ExpectedMapAttribute;
|
||||
IA32_MAP_ATTRIBUTE MapMask;
|
||||
RETURN_STATUS Status;
|
||||
IA32_MAP_ENTRY *Map;
|
||||
UINTN MapCount;
|
||||
IA32_PAGING_ENTRY *PagingEntry;
|
||||
|
||||
PagingMode = Paging4Level;
|
||||
PageTableBufferSize = 0;
|
||||
PageTable = 0;
|
||||
Buffer = NULL;
|
||||
MapAttribute.Uint64 = 0;
|
||||
MapMask.Uint64 = MAX_UINT64;
|
||||
MapAttribute.Bits.Present = 1;
|
||||
MapAttribute.Bits.ReadWrite = 1;
|
||||
MapAttribute.Bits.PageTableBaseAddress = (SIZE_2MB - SIZE_4KB) >> 12;
|
||||
//
|
||||
// Create Page table to cover [2M-4K, 4M], with ReadWrite = 1
|
||||
//
|
||||
Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, SIZE_2MB - SIZE_4KB, SIZE_4KB + SIZE_2MB, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
Buffer = AllocatePages (EFI_SIZE_TO_PAGES (PageTableBufferSize));
|
||||
Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, SIZE_2MB - SIZE_4KB, SIZE_4KB + SIZE_2MB, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
IsPageTableValid (PageTable, PagingMode);
|
||||
|
||||
MapCount = 0;
|
||||
Status = PageTableParse (PageTable, PagingMode, NULL, &MapCount);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
IsPageTableValid (PageTable, PagingMode);
|
||||
Map = AllocatePages (EFI_SIZE_TO_PAGES (MapCount));
|
||||
Status = PageTableParse (PageTable, PagingMode, Map, &MapCount);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
UT_ASSERT_EQUAL (MapCount, 1);
|
||||
UT_ASSERT_EQUAL (Map[0].LinearAddress, SIZE_2MB - SIZE_4KB);
|
||||
UT_ASSERT_EQUAL (Map[0].Length, SIZE_4KB + SIZE_2MB);
|
||||
ExpectedMapAttribute.Uint64 = MapAttribute.Uint64;
|
||||
UT_ASSERT_EQUAL (Map[0].Attribute.Uint64, ExpectedMapAttribute.Uint64);
|
||||
|
||||
//
|
||||
// Manually change ReadWrite to 0 for 3 level non-leaf entry, which covers [0,2M]
|
||||
// Then the map is:
|
||||
// [2M-4K,2M], R/W = 0
|
||||
// [2M ,4M], R/W = 1
|
||||
//
|
||||
PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTable; // Get 4 level entry
|
||||
PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)(PagingEntry->Pnle.Bits.PageTableBaseAddress << 12); // Get 3 level entry
|
||||
PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)(PagingEntry->Pnle.Bits.PageTableBaseAddress << 12); // Get 2 level entry
|
||||
PagingEntry->Uint64 = PagingEntry->Uint64 & (~(UINT64)0x2);
|
||||
MapCount = 0;
|
||||
Status = PageTableParse (PageTable, PagingMode, NULL, &MapCount);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
Map = AllocatePages (EFI_SIZE_TO_PAGES (MapCount));
|
||||
Status = PageTableParse (PageTable, PagingMode, Map, &MapCount);
|
||||
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
UT_ASSERT_EQUAL (MapCount, 2);
|
||||
UT_ASSERT_EQUAL (Map[0].LinearAddress, SIZE_2MB - SIZE_4KB);
|
||||
UT_ASSERT_EQUAL (Map[0].Length, SIZE_4KB);
|
||||
ExpectedMapAttribute.Uint64 = MapAttribute.Uint64;
|
||||
ExpectedMapAttribute.Bits.ReadWrite = 0;
|
||||
UT_ASSERT_EQUAL (Map[0].Attribute.Uint64, ExpectedMapAttribute.Uint64);
|
||||
|
||||
UT_ASSERT_EQUAL (Map[1].LinearAddress, SIZE_2MB);
|
||||
UT_ASSERT_EQUAL (Map[1].Length, SIZE_2MB);
|
||||
ExpectedMapAttribute.Uint64 = MapAttribute.Uint64;
|
||||
ExpectedMapAttribute.Bits.ReadWrite = 1;
|
||||
ExpectedMapAttribute.Bits.PageTableBaseAddress = SIZE_2MB >> 12;
|
||||
UT_ASSERT_EQUAL (Map[1].Attribute.Uint64, ExpectedMapAttribute.Uint64);
|
||||
|
||||
//
|
||||
// Set Page table [2M-4K, 2M+4K]'s ReadWrite = 1, [2M,2M+4K]'s ReadWrite is already 1
|
||||
// Just need to set [2M-4K,2M], won't need extra size, so the status should be success
|
||||
//
|
||||
MapAttribute.Bits.Present = 1;
|
||||
MapAttribute.Bits.ReadWrite = 1;
|
||||
PageTableBufferSize = 0;
|
||||
MapAttribute.Bits.PageTableBaseAddress = (SIZE_2MB - SIZE_4KB) >> 12;
|
||||
Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, SIZE_2MB - SIZE_4KB, SIZE_4KB * 2, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
return UNIT_TEST_PASSED;
|
||||
}
|
||||
|
||||
/**
|
||||
Check that won't merge entries
|
||||
|
||||
@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
|
||||
TestCaseManualNotMergeEntry (
|
||||
IN UNIT_TEST_CONTEXT Context
|
||||
)
|
||||
{
|
||||
UINTN PageTable;
|
||||
PAGING_MODE PagingMode;
|
||||
VOID *Buffer;
|
||||
UINTN PageTableBufferSize;
|
||||
IA32_MAP_ATTRIBUTE MapAttribute;
|
||||
IA32_MAP_ATTRIBUTE MapMask;
|
||||
RETURN_STATUS Status;
|
||||
UNIT_TEST_STATUS TestStatus;
|
||||
|
||||
PagingMode = Paging4Level1GB;
|
||||
PageTableBufferSize = 0;
|
||||
PageTable = 0;
|
||||
Buffer = NULL;
|
||||
MapAttribute.Uint64 = 0;
|
||||
MapMask.Uint64 = MAX_UINT64;
|
||||
MapAttribute.Bits.Present = 1;
|
||||
MapMask.Bits.Present = 1;
|
||||
|
||||
//
|
||||
// Create Page table to cover [0,4M], and [4M, 1G] is not present
|
||||
//
|
||||
Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, (UINT64)0, (UINT64)SIZE_2MB * 2, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
Buffer = AllocatePages (EFI_SIZE_TO_PAGES (PageTableBufferSize));
|
||||
Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, (UINT64)0, (UINT64)SIZE_2MB * 2, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
TestStatus = IsPageTableValid (PageTable, PagingMode);
|
||||
if (TestStatus != UNIT_TEST_PASSED) {
|
||||
return TestStatus;
|
||||
}
|
||||
|
||||
//
|
||||
// Let Page table to cover [0,1G], we assume it won't use a big 1G entry to cover whole range
|
||||
// It looks like the chioce is not bad, but sometime, we need to keep some small entry
|
||||
//
|
||||
PageTableBufferSize = 0;
|
||||
Status = PageTableMap (&PageTable, PagingMode, NULL, &PageTableBufferSize, (UINT64)0, (UINT64)SIZE_1GB, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
TestStatus = IsPageTableValid (PageTable, PagingMode);
|
||||
if (TestStatus != UNIT_TEST_PASSED) {
|
||||
return TestStatus;
|
||||
}
|
||||
|
||||
MapAttribute.Bits.Accessed = 1;
|
||||
PageTableBufferSize = 0;
|
||||
Status = PageTableMap (&PageTable, PagingMode, NULL, &PageTableBufferSize, (UINT64)0, (UINT64)SIZE_2MB, &MapAttribute, &MapMask);
|
||||
//
|
||||
// If it didn't use a big 1G entry to cover whole range, only change [0,2M] for some attribute won't need extra memory
|
||||
//
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
|
||||
return UNIT_TEST_PASSED;
|
||||
}
|
||||
|
||||
/**
|
||||
Check if the parent entry has different Nx attribute
|
||||
|
||||
@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
|
||||
TestCaseManualChangeNx (
|
||||
IN UNIT_TEST_CONTEXT Context
|
||||
)
|
||||
{
|
||||
UINTN PageTable;
|
||||
PAGING_MODE PagingMode;
|
||||
VOID *Buffer;
|
||||
UINTN PageTableBufferSize;
|
||||
IA32_MAP_ATTRIBUTE MapAttribute;
|
||||
IA32_MAP_ATTRIBUTE ExpectedMapAttribute;
|
||||
IA32_MAP_ATTRIBUTE MapMask;
|
||||
RETURN_STATUS Status;
|
||||
IA32_MAP_ENTRY *Map;
|
||||
UINTN MapCount;
|
||||
IA32_PAGING_ENTRY *PagingEntry;
|
||||
UNIT_TEST_STATUS TestStatus;
|
||||
|
||||
PagingMode = Paging4Level1GB;
|
||||
PageTableBufferSize = 0;
|
||||
PageTable = 0;
|
||||
Buffer = NULL;
|
||||
MapAttribute.Uint64 = 0;
|
||||
MapMask.Uint64 = MAX_UINT64;
|
||||
MapAttribute.Bits.Present = 1;
|
||||
MapAttribute.Bits.Nx = 0;
|
||||
|
||||
//
|
||||
// Create Page table to cover [0,2G], with Nx = 0
|
||||
//
|
||||
Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, (UINT64)0, (UINT64)SIZE_1GB * 2, &MapAttribute, &MapMask);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
Buffer = AllocatePages (EFI_SIZE_TO_PAGES (PageTableBufferSize));
|
||||
Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, (UINT64)0, (UINT64)SIZE_1GB * 2, &MapAttribute, &MapMask);
|
||||
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);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
TestStatus = IsPageTableValid (PageTable, PagingMode);
|
||||
if (TestStatus != UNIT_TEST_PASSED) {
|
||||
return TestStatus;
|
||||
}
|
||||
|
||||
Map = AllocatePages (EFI_SIZE_TO_PAGES (MapCount* sizeof (IA32_MAP_ENTRY)));
|
||||
Status = PageTableParse (PageTable, PagingMode, Map, &MapCount);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
UT_ASSERT_EQUAL (MapCount, 1);
|
||||
UT_ASSERT_EQUAL (Map[0].LinearAddress, 0);
|
||||
UT_ASSERT_EQUAL (Map[0].Length, SIZE_2GB);
|
||||
ExpectedMapAttribute.Uint64 = MapAttribute.Uint64;
|
||||
UT_ASSERT_EQUAL (Map[0].Attribute.Uint64, ExpectedMapAttribute.Uint64);
|
||||
|
||||
//
|
||||
// Manually change Nx to 1 for non-leaf entry, which covers [0,2G]
|
||||
//
|
||||
PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTable;
|
||||
PagingEntry->Uint64 = PagingEntry->Uint64 | BIT63;
|
||||
MapCount = 0;
|
||||
Status = PageTableParse (PageTable, PagingMode, NULL, &MapCount);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
Map = AllocatePages (EFI_SIZE_TO_PAGES (MapCount* sizeof (IA32_MAP_ENTRY)));
|
||||
Status = PageTableParse (PageTable, PagingMode, Map, &MapCount);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
UT_ASSERT_EQUAL (MapCount, 1);
|
||||
UT_ASSERT_EQUAL (Map[0].LinearAddress, 0);
|
||||
UT_ASSERT_EQUAL (Map[0].Length, SIZE_2GB);
|
||||
ExpectedMapAttribute.Bits.Nx = 1;
|
||||
UT_ASSERT_EQUAL (Map[0].Attribute.Uint64, ExpectedMapAttribute.Uint64);
|
||||
|
||||
//
|
||||
// Call library to change Nx to 0 for [0,1G]
|
||||
//
|
||||
Status = PageTableMap (&PageTable, PagingMode, NULL, &PageTableBufferSize, (UINT64)0, (UINT64)SIZE_1GB, &MapAttribute, &MapMask);
|
||||
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);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
|
||||
Map = AllocatePages (EFI_SIZE_TO_PAGES (MapCount* sizeof (IA32_MAP_ENTRY)));
|
||||
Status = PageTableParse (PageTable, PagingMode, Map, &MapCount);
|
||||
UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
|
||||
|
||||
//
|
||||
// There should be two ranges [0, 1G] with Nx = 0 and [1G, 2G] with Nx = 1
|
||||
//
|
||||
UT_ASSERT_EQUAL (MapCount, 2);
|
||||
UT_ASSERT_EQUAL (Map[0].LinearAddress, 0);
|
||||
UT_ASSERT_EQUAL (Map[0].Length, SIZE_1GB);
|
||||
ExpectedMapAttribute.Uint64 = MapAttribute.Uint64;
|
||||
UT_ASSERT_EQUAL (Map[0].Attribute.Uint64, ExpectedMapAttribute.Uint64);
|
||||
UT_ASSERT_EQUAL (Map[1].LinearAddress, SIZE_1GB);
|
||||
UT_ASSERT_EQUAL (Map[1].Length, SIZE_1GB);
|
||||
ExpectedMapAttribute.Uint64 = SIZE_1GB;
|
||||
ExpectedMapAttribute.Bits.Present = 1;
|
||||
ExpectedMapAttribute.Bits.Nx = 1;
|
||||
UT_ASSERT_EQUAL (Map[1].Attribute.Uint64, ExpectedMapAttribute.Uint64);
|
||||
return UNIT_TEST_PASSED;
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize the unit test framework, suite, and unit tests for the
|
||||
sample unit tests and run the unit tests.
|
||||
|
||||
@retval EFI_SUCCESS All test cases were dispatched.
|
||||
@retval EFI_OUT_OF_RESOURCES There are not enough resources available to
|
||||
initialize the unit tests.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UefiTestMain (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UNIT_TEST_FRAMEWORK_HANDLE Framework;
|
||||
UNIT_TEST_SUITE_HANDLE ManualTestCase;
|
||||
UNIT_TEST_SUITE_HANDLE RandomTestCase;
|
||||
|
||||
Framework = NULL;
|
||||
|
||||
DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION));
|
||||
|
||||
//
|
||||
// Start setting up 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;
|
||||
}
|
||||
|
||||
//
|
||||
// Populate the Manual Test Cases.
|
||||
//
|
||||
Status = CreateUnitTestSuite (&ManualTestCase, Framework, "Manual Test Cases", "CpuPageTableLib.Manual", NULL, NULL);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for Manual Test Cases\n"));
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
AddTestCase (ManualTestCase, "Check if the input parameters are not supported.", "Manual Test Case1", TestCaseForParameter, NULL, NULL, NULL);
|
||||
AddTestCase (ManualTestCase, "Check the case that modifying page table doesn't need extra buffer", "Manual Test Case2", TestCaseWhichNoNeedExtraSize, NULL, NULL, NULL);
|
||||
AddTestCase (ManualTestCase, "Check the case to map [0, 1G] to [8K, 1G+8K]", "Manual Test Case3", TestCase1Gmapto4K, NULL, NULL, NULL);
|
||||
AddTestCase (ManualTestCase, "Check won't merge entries", "Manual Test Case4", TestCaseManualNotMergeEntry, NULL, NULL, NULL);
|
||||
AddTestCase (ManualTestCase, "Check if the parent entry has different ReadWrite attribute", "Manual Test Case5", TestCaseManualChangeReadWrite, NULL, NULL, NULL);
|
||||
AddTestCase (ManualTestCase, "Check if the parent entry has different Nx attribute", "Manual Test Case6", TestCaseManualChangeNx, NULL, NULL, NULL);
|
||||
AddTestCase (ManualTestCase, "Check if the needed size is expected", "Manual Test Case7", TestCaseManualSizeNotMatch, NULL, NULL, NULL);
|
||||
|
||||
//
|
||||
// Populate the Random Test Cases.
|
||||
//
|
||||
Status = CreateUnitTestSuite (&RandomTestCase, Framework, "Random Test Cases", "CpuPageTableLib.Random", NULL, NULL);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for Random Test Cases\n"));
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
AddTestCase (RandomTestCase, "Random Test for Paging4Level", "Random Test Case1", TestCaseforRandomTest, NULL, NULL, &mTestContextPaging4Level);
|
||||
AddTestCase (RandomTestCase, "Random Test for Paging4Level1G", "Random Test Case2", TestCaseforRandomTest, NULL, NULL, &mTestContextPaging4Level1GB);
|
||||
AddTestCase (RandomTestCase, "Random Test for Paging5Level", "Random Test Case3", TestCaseforRandomTest, NULL, NULL, &mTestContextPaging5Level);
|
||||
AddTestCase (RandomTestCase, "Random Test for Paging5Level1G", "Random Test Case4", TestCaseforRandomTest, NULL, NULL, &mTestContextPaging5Level1GB);
|
||||
|
||||
//
|
||||
// Execute the tests.
|
||||
//
|
||||
Status = RunAllTestSuites (Framework);
|
||||
|
||||
EXIT:
|
||||
if (Framework) {
|
||||
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[]
|
||||
)
|
||||
{
|
||||
InitGlobalData (52);
|
||||
return UefiTestMain ();
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
## @file
|
||||
# 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
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010006
|
||||
BASE_NAME = CpuPageTableLibUnitTestHost
|
||||
FILE_GUID = D8DC32C2-7272-43A8-B145-1723BED8E119
|
||||
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]
|
||||
CpuPageTableLibUnitTestHost.c
|
||||
RandomTest.c
|
||||
TestHelper.c
|
||||
RandomNumber.c
|
||||
RandomTest.h
|
||||
CpuPageTableLibUnitTest.h
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
UefiCpuPkg/UefiCpuPkg.dec
|
||||
UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
|
||||
CryptoPkg/CryptoPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
BaseMemoryLib
|
||||
DebugLib
|
||||
CpuPageTableLib
|
||||
UnitTestLib
|
||||
MemoryAllocationLib
|
||||
BaseCryptLib
|
File diff suppressed because it is too large
Load Diff
|
@ -1,926 +0,0 @@
|
|||
/** @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;
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/** @file
|
||||
Internal header for Random test.
|
||||
|
||||
Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef RANDOM_TEST_H_
|
||||
#define RANDOM_TEST_H_
|
||||
|
||||
#include "CpuPageTableLibUnitTest.h"
|
||||
|
||||
typedef struct _ALLOCATE_PAGE_RECORDS ALLOCATE_PAGE_RECORDS;
|
||||
|
||||
typedef
|
||||
VOID *
|
||||
(EFIAPI *ALLOCATE_PAGES)(
|
||||
IN ALLOCATE_PAGE_RECORDS *PagesRecord,
|
||||
IN UINTN Pages
|
||||
);
|
||||
|
||||
typedef struct {
|
||||
VOID *Buffer;
|
||||
UINTN Pages;
|
||||
} ALLOCATE_PAGE_RECORD;
|
||||
|
||||
struct _ALLOCATE_PAGE_RECORDS {
|
||||
UINTN Count;
|
||||
UINTN MaxCount;
|
||||
ALLOCATE_PAGES AllocatePagesForPageTable;
|
||||
ALLOCATE_PAGE_RECORD Records[0];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
UINT64 LinearAddress;
|
||||
UINT64 Length;
|
||||
IA32_MAP_ATTRIBUTE Attribute;
|
||||
IA32_MAP_ATTRIBUTE Mask;
|
||||
} MAP_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
UINTN Count;
|
||||
UINTN InitCount;
|
||||
UINTN MaxCount;
|
||||
MAP_ENTRY Maps[10];
|
||||
} MAP_ENTRYS;
|
||||
|
||||
UINT64
|
||||
GetEntryFromPageTable (
|
||||
IN UINTN PageTable,
|
||||
IN PAGING_MODE PagingMode,
|
||||
IN UINT64 Address,
|
||||
OUT UINTN *Level
|
||||
);
|
||||
|
||||
#endif
|
|
@ -1,309 +0,0 @@
|
|||
/** @file
|
||||
helper file 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 "../CpuPageTable.h"
|
||||
|
||||
//
|
||||
// Global Data to validate if the page table is legal
|
||||
// mValidMaskNoLeaf[0] is not used
|
||||
// mValidMaskNoLeaf[1] ... mValidMaskNoLeaf [5] represent PTE ... PML5E
|
||||
// mValidMaskNoLeaf[Index] means if it is a valid no leaf entry, entry should equal to (entry & mValidMaskNoLeaf[Index])
|
||||
// mValidMaskLeaf[Index] means if it is a valid leaf entry, entry should equal to (entry & mValidMaskLeaf[Index])
|
||||
// mValidMaskLeafFlag[Index] means if it is a leaf entry, if and only if ((entry & mValidMaskLeafFlag[Index]) == mValidMaskLeafFlag[Index])
|
||||
//
|
||||
IA32_PAGING_ENTRY mValidMaskNoLeaf[6];
|
||||
IA32_PAGING_ENTRY mValidMaskLeaf[6];
|
||||
IA32_PAGING_ENTRY mValidMaskLeafFlag[6];
|
||||
|
||||
/**
|
||||
Init global data.
|
||||
|
||||
@param[in] MemorySpace Memory space
|
||||
**/
|
||||
VOID
|
||||
InitGlobalData (
|
||||
UINTN MemorySpace
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
ASSERT (MemorySpace <= 52);
|
||||
mValidMaskNoLeaf[0].Uint64 = 0;
|
||||
mValidMaskLeaf[0].Uint64 = 0;
|
||||
mValidMaskLeafFlag[0].Uint64 = 0;
|
||||
|
||||
//
|
||||
// Set common part for all kinds of entrys.
|
||||
//
|
||||
for (Index = 1; Index < 6; Index++) {
|
||||
mValidMaskNoLeaf[Index].Uint64 = MAX_UINT64;
|
||||
mValidMaskLeaf[Index].Uint64 = MAX_UINT64;
|
||||
|
||||
//
|
||||
// bit 51:M is reserved, and should be zero
|
||||
//
|
||||
if (MemorySpace - 1 < 51) {
|
||||
mValidMaskNoLeaf[Index].Uint64 = BitFieldWrite64 (mValidMaskNoLeaf[Index].Uint64, MemorySpace - 1, 51, 0);
|
||||
mValidMaskLeaf[Index].Uint64 = BitFieldWrite64 (mValidMaskLeaf[Index].Uint64, MemorySpace - 1, 51, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Handle mask for no leaf entry.
|
||||
//
|
||||
mValidMaskNoLeaf[1].Uint64 = 0; // PTE can't map to page structure.
|
||||
mValidMaskNoLeaf[2].Pnle.Bits.MustBeZero = 0; // for PML4E, bit 7 must be zero.
|
||||
mValidMaskNoLeaf[3].Pnle.Bits.MustBeZero = 0; // for PML5E, bit 7 must be zero.
|
||||
mValidMaskNoLeaf[4].Pml4.Bits.MustBeZero = 0; // for PML4E, bit 7 must be zero.
|
||||
mValidMaskNoLeaf[5].Pml4.Bits.MustBeZero = 0; // for PML5E, bit 7 must be zero.
|
||||
|
||||
//
|
||||
// Handle mask for leaf entry.
|
||||
// No need to modification for PTE, since it doesn't have extra reserved bit
|
||||
//
|
||||
mValidMaskLeaf[2].Uint64 = BitFieldWrite64 (mValidMaskLeaf[2].Uint64, 13, 20, 0); // bit 13-20 is reserved for PDE
|
||||
mValidMaskLeaf[3].Uint64 = BitFieldWrite64 (mValidMaskLeaf[2].Uint64, 13, 29, 0); // bit 13-29 is reserved for PDPTE
|
||||
mValidMaskLeaf[4].Uint64 = 0; // for PML4E, no possible to map to page.
|
||||
mValidMaskLeaf[5].Uint64 = 0; // for PML5E, no possible to map to page.
|
||||
|
||||
//
|
||||
// Handle Flags to indicate it is a leaf entry.
|
||||
// for PML4E and PML5E, no possible to map to page, so the flag should be MAX_UINT64.
|
||||
//
|
||||
mValidMaskLeafFlag[1].Pce.Present = 1; // For PTE, as long as it is present, it maps to page
|
||||
//
|
||||
// For PDE and PDPTE, the bit 7 should be set to map to pages
|
||||
//
|
||||
mValidMaskLeafFlag[2].Pde2M.Bits.MustBeOne = 1;
|
||||
mValidMaskLeafFlag[2].Pde2M.Bits.Present = 1;
|
||||
mValidMaskLeafFlag[3].Pde2M.Bits.MustBeOne = 1;
|
||||
mValidMaskLeafFlag[3].Pde2M.Bits.Present = 1;
|
||||
mValidMaskLeafFlag[4].Uint64 = MAX_UINT64;
|
||||
mValidMaskLeafFlag[5].Uint64 = MAX_UINT64;
|
||||
}
|
||||
|
||||
/**
|
||||
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
|
||||
IsPageTableEntryValid (
|
||||
IN IA32_PAGING_ENTRY *PagingEntry,
|
||||
IN UINTN Level,
|
||||
IN UINTN MaxLeafLevel,
|
||||
IN UINT64 Address
|
||||
)
|
||||
{
|
||||
UINT64 Index;
|
||||
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) {
|
||||
DEBUG ((DEBUG_ERROR, "ERROR: Level %d entry 0x%lx is a leaf entry, but max leaf level is %d \n", Level, PagingEntry->Uint64, MaxLeafLevel));
|
||||
UT_ASSERT_TRUE (Level <= MaxLeafLevel);
|
||||
}
|
||||
|
||||
if ((PagingEntry->Uint64 & mValidMaskLeaf[Level].Uint64) != PagingEntry->Uint64) {
|
||||
DEBUG ((DEBUG_ERROR, "ERROR: Level %d Leaf entry is 0x%lx, which reserved bit is set \n", Level, 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);
|
||||
}
|
||||
|
||||
ChildPageEntry = (IA32_PAGING_ENTRY *)(UINTN)(((UINTN)(PagingEntry->Pnle.Bits.PageTableBaseAddress)) << 12);
|
||||
for (Index = 0; Index < 512; Index++) {
|
||||
Status = IsPageTableEntryValid (&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
|
||||
IsPageTableValid (
|
||||
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 = IsPageTableEntryValid (&PagingEntry[Index], MaxLevel, MaxLeafLevel, Index << (9 * MaxLevel + 3));
|
||||
if (Status != UNIT_TEST_PASSED) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the leaf entry for a given linear address from one entry in page table
|
||||
|
||||
@param[in] PagingEntry The entry in page table which covers the linear address
|
||||
@param[in, out] Level On input, is the level of PagingEntry.
|
||||
On outout, is the level of the leaf entry
|
||||
@param[in] MaxLeafLevel Max leaf entry level.
|
||||
@param[in] LinearAddress The linear address.
|
||||
|
||||
@retval Leaf entry.
|
||||
**/
|
||||
UINT64
|
||||
GetEntryFromSubPageTable (
|
||||
IN IA32_PAGING_ENTRY *PagingEntry,
|
||||
IN OUT UINTN *Level,
|
||||
IN UINTN MaxLeafLevel,
|
||||
IN UINT64 Address
|
||||
)
|
||||
{
|
||||
UINT64 Index;
|
||||
IA32_PAGING_ENTRY *ChildPageEntry;
|
||||
|
||||
if (PagingEntry->Pce.Present == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((PagingEntry->Uint64 & mValidMaskLeafFlag[*Level].Uint64) == mValidMaskLeafFlag[*Level].Uint64) {
|
||||
//
|
||||
// It is a Leaf
|
||||
//
|
||||
return PagingEntry->Uint64;
|
||||
}
|
||||
|
||||
//
|
||||
// Not a leaf
|
||||
//
|
||||
ChildPageEntry = (IA32_PAGING_ENTRY *)(UINTN)(((UINTN)(PagingEntry->Pnle.Bits.PageTableBaseAddress)) << 12);
|
||||
*Level = *Level -1;
|
||||
Index = Address >> (*Level * 9 + 3);
|
||||
ASSERT (Index == (Index & ((1<< 9) - 1)));
|
||||
|
||||
return GetEntryFromSubPageTable (&ChildPageEntry[Index], Level, MaxLeafLevel, Address - (Index << (9 * *Level + 3)));
|
||||
}
|
||||
|
||||
/**
|
||||
Get the leaf entry for a given linear address from a page table
|
||||
|
||||
@param[in] PageTable The pointer to the page table.
|
||||
@param[in] PagingMode The paging mode.
|
||||
@param[in] LinearAddress The linear address.
|
||||
@param[out] Level leaf entry's level.
|
||||
|
||||
@retval Leaf entry.
|
||||
**/
|
||||
UINT64
|
||||
GetEntryFromPageTable (
|
||||
IN UINTN PageTable,
|
||||
IN PAGING_MODE PagingMode,
|
||||
IN UINT64 Address,
|
||||
OUT UINTN *Level
|
||||
)
|
||||
{
|
||||
UINTN MaxLevel;
|
||||
UINTN MaxLeafLevel;
|
||||
UINT64 Index;
|
||||
IA32_PAGING_ENTRY *PagingEntry;
|
||||
|
||||
if ((PagingMode == Paging32bit) || (PagingMode == PagingPae) || (PagingMode >= PagingModeMax)) {
|
||||
//
|
||||
// 32bit paging is never supported.
|
||||
// PAE paging will be supported later.
|
||||
//
|
||||
return 0;
|
||||
}
|
||||
|
||||
MaxLeafLevel = (UINT8)PagingMode;
|
||||
MaxLevel = (UINT8)(PagingMode >> 8);
|
||||
|
||||
Index = Address >> (MaxLevel * 9 + 3);
|
||||
ASSERT (Index == (Index & ((1<< 9) - 1)));
|
||||
PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTable;
|
||||
*Level = MaxLevel;
|
||||
|
||||
return GetEntryFromSubPageTable (&PagingEntry[Index], Level, MaxLeafLevel, Address - (Index << (9 * MaxLevel + 3)));
|
||||
}
|
||||
|
||||
/**
|
||||
Get max physical adrress supported by specific page mode
|
||||
|
||||
@param[in] Mode The paging mode.
|
||||
|
||||
@retval max address.
|
||||
**/
|
||||
UINT64
|
||||
GetMaxAddress (
|
||||
IN PAGING_MODE Mode
|
||||
)
|
||||
{
|
||||
switch (Mode) {
|
||||
case Paging32bit:
|
||||
case PagingPae:
|
||||
return SIZE_4GB;
|
||||
|
||||
case Paging4Level:
|
||||
case Paging4Level1GB:
|
||||
case Paging5Level:
|
||||
case Paging5Level1GB:
|
||||
return 1ull << MIN (12 + (Mode >> 8) * 9, 52);
|
||||
|
||||
default:
|
||||
ASSERT (0);
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -20,10 +20,6 @@
|
|||
|
||||
[LibraryClasses]
|
||||
MtrrLib|UefiCpuPkg/Library/MtrrLib/MtrrLib.inf
|
||||
CpuPageTableLib|UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf
|
||||
OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf
|
||||
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/UnitTestHostBaseCryptLib.inf
|
||||
RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf
|
||||
|
||||
[PcdsPatchableInModule]
|
||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuNumberOfReservedVariableMtrrs|0
|
||||
|
@ -33,8 +29,3 @@
|
|||
# Build HOST_APPLICATION that tests the MtrrLib
|
||||
#
|
||||
UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTestHost.inf
|
||||
|
||||
#
|
||||
# Build HOST_APPLICATION that tests the CpuPageTableLib
|
||||
#
|
||||
UefiCpuPkg/Library/CpuPageTableLib/UnitTest/CpuPageTableLibUnitTestHost.inf
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
## "<ErrorID>", "<KeyWord>"
|
||||
## ]
|
||||
"ExceptionList": [
|
||||
"8006", "main"
|
||||
],
|
||||
## Both file path and directory path are accepted.
|
||||
"IgnoreFiles": [
|
||||
|
@ -39,8 +38,7 @@
|
|||
],
|
||||
# For host based unit tests
|
||||
"AcceptableDependencies-HOST_APPLICATION":[
|
||||
"UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec",
|
||||
"CryptoPkg/CryptoPkg.dec"
|
||||
"UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec"
|
||||
],
|
||||
# For UEFI shell based apps
|
||||
"AcceptableDependencies-UEFI_APPLICATION":[],
|
||||
|
|
Loading…
Reference in New Issue