Reduce the number of random tests. In previous patch, non-1:1 mapping is enbaled and it may need more than an hour and a half for the CI test, which may lead to CI timeout. Reduce the number of random test count to pass the CI. Signed-off-by: Dun Tan <dun.tan@intel.com> Cc: Eric Dong <eric.dong@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Tested-by: Gerd Hoffmann <kraxel@redhat.com> Acked-by: Gerd Hoffmann <kraxel@redhat.com>
		
			
				
	
	
		
			920 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			920 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  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"
 | 
						|
 | 
						|
// ----------------------------------------------------------------------- PageMode--TestCount-TestRangeCount---RandomOptions
 | 
						|
static CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT  mTestContextPaging4Level    = { Paging4Level, 30, 20, USE_RANDOM_ARRAY };
 | 
						|
static CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT  mTestContextPaging4Level1GB = { Paging4Level1GB, 30, 20, USE_RANDOM_ARRAY };
 | 
						|
static CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT  mTestContextPaging5Level    = { Paging5Level, 30, 20, USE_RANDOM_ARRAY };
 | 
						|
static CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT  mTestContextPaging5Level1GB = { Paging5Level1GB, 30, 20, USE_RANDOM_ARRAY };
 | 
						|
static CPU_PAGE_TABLE_LIB_RANDOM_TEST_CONTEXT  mTestContextPagingPae       = { PagingPae, 30, 20, 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, NULL), 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, NULL), 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, NULL), 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, 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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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;
 | 
						|
  MapMask.Uint64              = MAX_UINT64;
 | 
						|
  MapAttribute.Uint64         = (SIZE_2MB - SIZE_4KB);
 | 
						|
  MapAttribute.Bits.Present   = 1;
 | 
						|
  MapAttribute.Bits.ReadWrite = 1;
 | 
						|
  //
 | 
						|
  // 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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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)IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (PagingEntry); // Get 3 level entry
 | 
						|
  PagingEntry         = (IA32_PAGING_ENTRY *)(UINTN)IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (PagingEntry); // 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 + SIZE_4KB;
 | 
						|
  ExpectedMapAttribute.Bits.ReadWrite = 1;
 | 
						|
  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.Uint64         = SIZE_2MB - SIZE_4KB;
 | 
						|
  MapAttribute.Bits.Present   = 1;
 | 
						|
  MapAttribute.Bits.ReadWrite = 1;
 | 
						|
  PageTableBufferSize         = 0;
 | 
						|
  Status                      = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, SIZE_2MB - SIZE_4KB, SIZE_4KB * 2, &MapAttribute, &MapMask, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  //
 | 
						|
  // 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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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, NULL);
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if the input Mask and Attribute is as expected when creating new page table or
 | 
						|
  updating existing page table.
 | 
						|
 | 
						|
  @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
 | 
						|
TestCaseToCheckMapMaskAndAttr (
 | 
						|
  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;
 | 
						|
 | 
						|
  PagingMode                = Paging4Level;
 | 
						|
  PageTableBufferSize       = 0;
 | 
						|
  PageTable                 = 0;
 | 
						|
  Buffer                    = NULL;
 | 
						|
  MapAttribute.Uint64       = 0;
 | 
						|
  MapAttribute.Bits.Present = 1;
 | 
						|
  MapMask.Uint64            = 0;
 | 
						|
  MapMask.Bits.Present      = 1;
 | 
						|
  //
 | 
						|
  // Create Page table to cover [0, 2G]. All fields of MapMask should be set.
 | 
						|
  //
 | 
						|
  Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, 0, SIZE_2GB, &MapAttribute, &MapMask, NULL);
 | 
						|
  UT_ASSERT_EQUAL (Status, RETURN_INVALID_PARAMETER);
 | 
						|
  MapMask.Uint64 = MAX_UINT64;
 | 
						|
  Status         = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, 0, SIZE_2GB, &MapAttribute, &MapMask, NULL);
 | 
						|
  UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
 | 
						|
  Buffer = AllocatePages (EFI_SIZE_TO_PAGES (PageTableBufferSize));
 | 
						|
  Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, 0, SIZE_2GB, &MapAttribute, &MapMask, NULL);
 | 
						|
  UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
 | 
						|
 | 
						|
  //
 | 
						|
  // Update Page table to set [2G - 8K, 2G] from present to non-present. All fields of MapMask except present should not be set.
 | 
						|
  //
 | 
						|
  PageTableBufferSize    = 0;
 | 
						|
  MapAttribute.Uint64    = 0;
 | 
						|
  MapMask.Uint64         = 0;
 | 
						|
  MapMask.Bits.Present   = 1;
 | 
						|
  MapMask.Bits.ReadWrite = 1;
 | 
						|
  Status                 = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, SIZE_2GB - SIZE_8KB, SIZE_8KB, &MapAttribute, &MapMask, NULL);
 | 
						|
  UT_ASSERT_EQUAL (Status, RETURN_INVALID_PARAMETER);
 | 
						|
  MapMask.Bits.ReadWrite = 0;
 | 
						|
  Status                 = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, SIZE_2GB - SIZE_8KB, SIZE_8KB, &MapAttribute, &MapMask, NULL);
 | 
						|
  UT_ASSERT_EQUAL (Status, RETURN_BUFFER_TOO_SMALL);
 | 
						|
  Buffer = AllocatePages (EFI_SIZE_TO_PAGES (PageTableBufferSize));
 | 
						|
  Status = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, SIZE_2GB - SIZE_8KB, SIZE_8KB, &MapAttribute, &MapMask, NULL);
 | 
						|
  UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
 | 
						|
 | 
						|
  //
 | 
						|
  // Still set [2G - 8K, 2G] as not present, this case is permitted. But set [2G - 8K, 2G] as RW is not permitted.
 | 
						|
  //
 | 
						|
  PageTableBufferSize  = 0;
 | 
						|
  MapAttribute.Uint64  = 0;
 | 
						|
  MapMask.Uint64       = 0;
 | 
						|
  MapMask.Bits.Present = 1;
 | 
						|
  Status               = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, SIZE_2GB - SIZE_8KB, SIZE_8KB, &MapAttribute, &MapMask, NULL);
 | 
						|
  UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
 | 
						|
  MapAttribute.Bits.ReadWrite = 1;
 | 
						|
  MapMask.Bits.ReadWrite      = 1;
 | 
						|
  Status                      = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, SIZE_2GB - SIZE_8KB, SIZE_8KB, &MapAttribute, &MapMask, NULL);
 | 
						|
  UT_ASSERT_EQUAL (Status, RETURN_INVALID_PARAMETER);
 | 
						|
 | 
						|
  //
 | 
						|
  // Update Page table to set [2G - 8K, 2G] as present and RW. All fields of MapMask should be set.
 | 
						|
  //
 | 
						|
  PageTableBufferSize         = 0;
 | 
						|
  MapAttribute.Uint64         = SIZE_2GB - SIZE_8KB;
 | 
						|
  MapAttribute.Bits.ReadWrite = 1;
 | 
						|
  MapAttribute.Bits.Present   = 1;
 | 
						|
  MapMask.Uint64              = 0;
 | 
						|
  MapMask.Bits.ReadWrite      = 1;
 | 
						|
  MapMask.Bits.Present        = 1;
 | 
						|
  Status                      = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, SIZE_2GB - SIZE_8KB, SIZE_8KB, &MapAttribute, &MapMask, NULL);
 | 
						|
  UT_ASSERT_EQUAL (Status, RETURN_INVALID_PARAMETER);
 | 
						|
  MapMask.Uint64 = MAX_UINT64;
 | 
						|
  Status         = PageTableMap (&PageTable, PagingMode, Buffer, &PageTableBufferSize, SIZE_2GB - SIZE_8KB, SIZE_8KB, &MapAttribute, &MapMask, NULL);
 | 
						|
  UT_ASSERT_EQUAL (Status, RETURN_SUCCESS);
 | 
						|
 | 
						|
  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, 2G-8k] with RW = 0 and [2G-8k, 2G] with RW = 1
 | 
						|
  //
 | 
						|
  UT_ASSERT_EQUAL (MapCount, 2);
 | 
						|
  UT_ASSERT_EQUAL (Map[0].LinearAddress, 0);
 | 
						|
  UT_ASSERT_EQUAL (Map[0].Length, SIZE_2GB - SIZE_8KB);
 | 
						|
  ExpectedMapAttribute.Uint64       =  0;
 | 
						|
  ExpectedMapAttribute.Bits.Present =  1;
 | 
						|
  UT_ASSERT_EQUAL (Map[0].Attribute.Uint64, ExpectedMapAttribute.Uint64);
 | 
						|
  UT_ASSERT_EQUAL (Map[1].LinearAddress, SIZE_2GB - SIZE_8KB);
 | 
						|
  UT_ASSERT_EQUAL (Map[1].Length, SIZE_8KB);
 | 
						|
  ExpectedMapAttribute.Uint64         =   SIZE_2GB - SIZE_8KB;
 | 
						|
  ExpectedMapAttribute.Bits.Present   = 1;
 | 
						|
  ExpectedMapAttribute.Bits.ReadWrite = 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);
 | 
						|
  AddTestCase (ManualTestCase, "Check MapMask when creating new page table or mapping not-present range", "Manual Test Case8", TestCaseToCheckMapMaskAndAttr, 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);
 | 
						|
  AddTestCase (RandomTestCase, "Random Test for PagingPae", "Random Test Case5", TestCaseforRandomTest, NULL, NULL, &mTestContextPagingPae);
 | 
						|
 | 
						|
  //
 | 
						|
  // 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 ();
 | 
						|
}
 |