UnitTestFrameworkPkg/MemoryAllocationLibPosix: Add allocate below address

Add HostMemoryAllocationBelowAddressLib class and implementation that
uses OS specific services to perform pool and page allocations below
a specified address in a host based unit test application execution
environment. This library class is only required for mocking buffers
that are assumed to be below a specific address by code under test.

Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com>
This commit is contained in:
Michael D Kinney 2024-11-25 11:34:54 -08:00 committed by mergify[bot]
parent 5f97d5391e
commit e78fb8a366
8 changed files with 778 additions and 1 deletions

View File

@ -0,0 +1,90 @@
/** @file
HostMemoryAllocationBelowAddressLib class
Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef HOST_MEMORY_ALLOCATION_BELOW_ADDRESS_LIB_H_
/**
Allocate memory below a specifies address.
@param[in] MaximumAddress The address below which the memory allocation must
be performed.
@param[in] Length The size, in bytes, of the memory allocation.
@retval !NULL Pointer to the allocated memory.
@retval NULL The memory allocation failed.
**/
VOID *
EFIAPI
HostAllocatePoolBelowAddress (
IN UINT64 MaximumAddress,
IN UINT64 Length
);
/**
Free memory allocated with AllocateMemoryHostAllocatePoolBelowAddress().
@param[in] Address Pointer to buffer previously allocated with
HostAllocatePoolBelowAddress().
**/
VOID
EFIAPI
HostFreePoolBelowAddress (
IN VOID *Address
);
/**
Allocates one or more 4KB pages below a specified address at a specified
alignment.
Allocates the number of 4KB pages specified by Pages below MaximumAddress with
an alignment specified by Alignment. The allocated buffer is returned. If
Pages is 0, then NULL is returned. If there is not enough memory below the
requested address at the specified alignment remaining to satisfy the request,
then NULL is returned.
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
@param[in] MaximumAddress The address below which the memory allocation must
@param[in] Pages The number of 4 KB pages to allocate.
@param[in] Alignment The requested alignment of the allocation. Must be
a power of two. If Alignment is zero, then byte
alignment is used.
@return A pointer to the allocated buffer or NULL if allocation fails.
**/
VOID *
EFIAPI
HostAllocateAlignedPagesBelowAddress (
IN UINT64 MaximumAddress,
IN UINTN Pages,
IN UINT64 Alignment
);
/**
Frees one or more 4KB pages that were previously allocated with
HostAllocateAlignedPagesBelowAddress().
Frees the number of 4KB pages specified by Pages from the buffer specified by
Buffer. Buffer must have been allocated with HostAllocateAlignedPagesBelowAddress().
If it is not possible to free allocated pages, then this function will perform
no actions.
If Buffer was not allocated with HostAllocateAlignedPagesBelowAddress(), then
ASSERT(). If Pages is zero, then ASSERT().
@param[in] Buffer The pointer to the buffer of pages to free.
@param[in] Pages The number of 4 KB pages to free.
**/
VOID
EFIAPI
HostFreeAlignedPagesBelowAddress (
IN VOID *Buffer,
IN UINTN Pages
);
#endif

View File

@ -0,0 +1,438 @@
/** @file
Instance of Memory Below Address Allocation Library based on Windows APIs
and Linux APIs.
Uses Windows APIs VirtualAlloc() and VirtualFree() to allocate and free memory
below a specified virtual address.
Uses Linux APIs mmap() and munmap() to allocate and free memory below a
specified virtual address.
Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#if defined (_WIN32) || defined (_WIN64)
#include "WinInclude.h"
#elif defined (__linux__)
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#else
#error Unsupported target
#endif
#include <Library/HostMemoryAllocationBelowAddressLib.h>
#include <Library/DebugLib.h>
///
/// Signature for PAGE_HEAD_BELOW_ADDRESS structure
/// Used to verify that buffer being freed was allocated by this library.
///
#define PAGE_HEAD_BELOW_ADDRESS_PRIVATE_SIGNATURE SIGNATURE_64 ('P', 'A', 'H', 'B', 'e', 'l', 'A', 'd')
///
/// Structure placed immediately before an aligned allocation to store the
/// information required to free the entire allocated buffer.
///
typedef struct {
UINT64 Signature;
VOID *AllocatedBuffer;
UINTN TotalPages;
VOID *AlignedBuffer;
UINTN AlignedPages;
} PAGE_HEAD_BELOW_ADDRESS;
///
/// Signature for POOL_HEAD_BELOW_ADDRESS structure
/// Used to verify that buffer being freed was allocated by this library.
///
#define POOL_HEAD_BELOW_ADDRESS_PRIVATE_SIGNATURE SIGNATURE_64 ('P', 'O', 'H', 'B', 'e', 'l', 'A', 'd')
///
/// Structure placed immediately before an pool allocation to store the
/// information required to free the entire allocated buffer.
///
typedef struct {
UINT64 Signature;
UINT64 TotalSize;
} POOL_HEAD_BELOW_ADDRESS;
//
// Lowest address that can be allocated by this library
//
#define MINIMUM_ALLOCATION_ADDRESS BASE_64KB
//
// The page size of the host
//
static UINTN mPageSize = 0;
/**
Use system services to get the host page size.
@return Host page size in bytes.
**/
static
UINTN
HostGetPageSize (
VOID
)
{
#if defined (_WIN32) || defined (_WIN64)
SYSTEM_INFO SystemInfo;
GetSystemInfo (&SystemInfo);
return (UINTN)SystemInfo.dwPageSize;
#elif defined (__linux__)
return sysconf (_SC_PAGESIZE);
#else
return 0;
#endif
}
/**
Use system services to allocate a buffer between a minimum and maximum
address aligned to the requested page size.
@param[in] MaximumAddress The address below which the memory allocation must
be performed.
@param[in] Length The size, in bytes, of the memory allocation.
@retval !NULL Pointer to the allocated memory.
@retval NULL The memory allocation failed.
**/
static
VOID *
HostAllocateBufferInRange (
UINTN MaximumAddress,
UINTN Length
)
{
UINTN Address;
VOID *AllocatedAddress;
if (mPageSize == 0) {
mPageSize = HostGetPageSize ();
if (mPageSize == 0) {
return NULL;
}
}
//
// Round maximum address down to the nearest page boundary
//
MaximumAddress &= ~(mPageSize - 1);
for (Address = MaximumAddress; Address >= MINIMUM_ALLOCATION_ADDRESS; Address -= mPageSize) {
#if defined (_WIN32) || defined (_WIN64)
AllocatedAddress = VirtualAlloc (
(VOID *)Address,
Length,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE
);
if (AllocatedAddress != NULL) {
return AllocatedAddress;
}
#elif defined (__linux__)
AllocatedAddress = mmap (
(VOID *)Address,
Length,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE,
-1,
0
);
if (AllocatedAddress != MAP_FAILED) {
return AllocatedAddress;
}
#else
return NULL;
#endif
}
return NULL;
}
/**
Use system services to free memory allocated with HostAllocateBufferInRange().
@param[in] Buffer Pointer to buffer previously allocated with
HostAllocateBufferInRange().
@param[in] Length Length, in bytes, of buffer previously allocated with
HostAllocateBufferInRange().
**/
static
VOID
HostFreeBufferInRange (
IN VOID *Buffer,
IN UINTN Length
)
{
#if defined (_WIN32) || defined (_WIN64)
if (!VirtualFree (Buffer, 0, MEM_RELEASE)) {
ASSERT (FALSE);
}
#elif defined (__linux__)
if (munmap (Buffer, Length) == -1) {
ASSERT (FALSE);
}
#endif
}
/**
Allocate memory below a specific address.
@param[in] MaximumAddress The address below which the memory allocation must
be performed.
@param[in] Length The size, in bytes, of the memory allocation.
@retval !NULL Pointer to the allocated memory.
@retval NULL The memory allocation failed.
**/
VOID *
EFIAPI
HostAllocatePoolBelowAddress (
IN UINT64 MaximumAddress,
IN UINT64 Length
)
{
VOID *AllocatedAddress;
POOL_HEAD_BELOW_ADDRESS *PoolHead;
if (Length == 0) {
return NULL;
}
//
// Limit maximum address to the largest supported virtual address
//
MaximumAddress = MIN (MaximumAddress, MAX_UINTN);
//
// Increase requested allocation length by the size of the pool header
//
Length += sizeof (POOL_HEAD_BELOW_ADDRESS);
//
// Make sure allocation length is smaller than maximum address
//
if (Length > MaximumAddress) {
DEBUG ((DEBUG_ERROR, "HostAllocatePoolBelowAddress: Length > MaximumAddress\n"));
return NULL;
}
//
// Reduce maximum address by the requested allocation length
//
MaximumAddress -= Length;
AllocatedAddress = HostAllocateBufferInRange (
(UINTN)MaximumAddress,
(UINTN)Length
);
if (AllocatedAddress == NULL) {
DEBUG ((DEBUG_ERROR, "HostAllocatePoolBelowAddress: HostAllocateBufferInRange failed\n"));
return NULL;
}
DEBUG_CLEAR_MEMORY (AllocatedAddress, (UINTN)Length);
PoolHead = (POOL_HEAD_BELOW_ADDRESS *)AllocatedAddress;
PoolHead->Signature = POOL_HEAD_BELOW_ADDRESS_PRIVATE_SIGNATURE;
PoolHead->TotalSize = Length;
return (VOID *)(PoolHead + 1);
}
/**
Free memory allocated with HostAllocatePoolBelowAddress().
@param[in] Buffer Pointer to buffer previously allocated with
HostAllocatePoolBelowAddress().
**/
VOID
EFIAPI
HostFreePoolBelowAddress (
IN VOID *Buffer
)
{
POOL_HEAD_BELOW_ADDRESS *PoolHead;
UINTN Length;
ASSERT (Buffer != NULL);
PoolHead = ((POOL_HEAD_BELOW_ADDRESS *)Buffer) - 1;
ASSERT (PoolHead != NULL);
ASSERT (PoolHead->Signature == POOL_HEAD_BELOW_ADDRESS_PRIVATE_SIGNATURE);
ASSERT (PoolHead->TotalSize >= sizeof (POOL_HEAD_BELOW_ADDRESS));
ASSERT (PoolHead->TotalSize <= MAX_UINTN);
Length = (UINTN)PoolHead->TotalSize;
DEBUG_CLEAR_MEMORY (PoolHead, Length);
HostFreeBufferInRange (PoolHead, Length);
}
/**
Allocates one or more 4KB pages below a specified address at a specified
alignment.
Allocates the number of 4KB pages specified by Pages below MaximumAddress with
an alignment specified by Alignment. The allocated buffer is returned. If
Pages is 0, then NULL is returned. If there is not enough memory below the
requested address at the specified alignment remaining to satisfy the request,
then NULL is returned.
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
@param[in] MaximumAddress The address below which the memory allocation must
@param[in] Pages The number of 4 KB pages to allocate.
@param[in] Alignment The requested alignment of the allocation. Must be
a power of two. If Alignment is zero, then byte
alignment is used.
@return A pointer to the allocated buffer or NULL if allocation fails.
**/
VOID *
EFIAPI
HostAllocateAlignedPagesBelowAddress (
IN UINT64 MaximumAddress,
IN UINTN Pages,
IN UINT64 Alignment
)
{
PAGE_HEAD_BELOW_ADDRESS PageHead;
PAGE_HEAD_BELOW_ADDRESS *PageHeadPtr;
UINTN AlignmentMask;
UINTN Length;
if (Pages == 0) {
return NULL;
}
//
// Make sure alignment is a power of two
//
if ((Alignment & (Alignment - 1)) != 0) {
DEBUG ((DEBUG_ERROR, "HostAllocateAlignedPagesBelowAddress: Alignment is not a power of two\n"));
return NULL;
}
//
// Make sure alignment is smaller than the largest supported virtual address
//
if (Alignment > MAX_UINTN) {
DEBUG ((DEBUG_ERROR, "HostAllocateAlignedPagesBelowAddress: Alignment > MAX_UINTN\n"));
return NULL;
}
//
// Make sure alignment is at least 4KB
//
Alignment = MAX (Alignment, SIZE_4KB);
//
// Initialize local page head structure
//
PageHead.Signature = PAGE_HEAD_BELOW_ADDRESS_PRIVATE_SIGNATURE;
PageHead.AlignedPages = Pages;
PageHead.TotalPages = Pages + 2 * EFI_SIZE_TO_PAGES ((UINTN)Alignment);
//
// Limit maximum address to the largest supported virtual address
//
MaximumAddress = MIN (MaximumAddress, MAX_UINTN);
//
// Make sure total page allocation fits below maximum address
//
if (PageHead.TotalPages >= EFI_SIZE_TO_PAGES (MaximumAddress)) {
DEBUG ((DEBUG_ERROR, "HostAllocateAlignedPagesBelowAddress: TotalPages >= MaximumAddress\n"));
return NULL;
}
//
// Determine the length of the allocation in bytes
//
Length = EFI_PAGES_TO_SIZE (PageHead.TotalPages);
//
// Reduce maximum address by the total allocation length
//
MaximumAddress -= Length;
//
// Allocate buffer large enough to support aligned page request
//
PageHead.AllocatedBuffer = HostAllocateBufferInRange (
(UINTN)MaximumAddress,
Length
);
if (PageHead.AllocatedBuffer == NULL) {
DEBUG ((DEBUG_ERROR, "HostAllocateAlignedPagesBelowAddress: HostAllocateBufferInRange failed\n"));
return NULL;
}
DEBUG_CLEAR_MEMORY (PageHead.AllocatedBuffer, Length);
AlignmentMask = ((UINTN)Alignment - 1);
PageHead.AlignedBuffer = (VOID *)(((UINTN)PageHead.AllocatedBuffer + AlignmentMask) & ~AlignmentMask);
if ((UINTN)PageHead.AlignedBuffer - (UINTN)PageHead.AllocatedBuffer < sizeof (PAGE_HEAD_BELOW_ADDRESS)) {
PageHead.AlignedBuffer = (VOID *)((UINTN)PageHead.AlignedBuffer + (UINTN)Alignment);
}
PageHeadPtr = (PAGE_HEAD_BELOW_ADDRESS *)((UINTN)PageHead.AlignedBuffer) - 1;
memcpy (PageHeadPtr, &PageHead, sizeof (PageHead));
return PageHead.AlignedBuffer;
}
/**
Frees one or more 4KB pages that were previously allocated with
HostAllocateAlignedPagesBelowAddress().
Frees the number of 4KB pages specified by Pages from the buffer specified by
Buffer. Buffer must have been allocated with HostAllocateAlignedPagesBelowAddress().
If it is not possible to free allocated pages, then this function will perform
no actions.
If Buffer was not allocated with HostAllocateAlignedPagesBelowAddress(), then
ASSERT(). If Pages is zero, then ASSERT().
@param[in] Buffer The pointer to the buffer of pages to free.
@param[in] Pages The number of 4 KB pages to free.
**/
VOID
EFIAPI
HostFreeAlignedPagesBelowAddress (
IN VOID *Buffer,
IN UINTN Pages
)
{
PAGE_HEAD_BELOW_ADDRESS *PageHeadPtr;
VOID *AllocatedBuffer;
UINTN Length;
ASSERT (Buffer != NULL);
PageHeadPtr = ((PAGE_HEAD_BELOW_ADDRESS *)Buffer) - 1;
ASSERT (PageHeadPtr != NULL);
ASSERT (PageHeadPtr->Signature == PAGE_HEAD_BELOW_ADDRESS_PRIVATE_SIGNATURE);
ASSERT (PageHeadPtr->AlignedPages == Pages);
ASSERT (PageHeadPtr->AllocatedBuffer != NULL);
AllocatedBuffer = PageHeadPtr->AllocatedBuffer;
Length = EFI_PAGES_TO_SIZE (PageHeadPtr->TotalPages);
DEBUG_CLEAR_MEMORY (AllocatedBuffer, Length);
HostFreeBufferInRange (AllocatedBuffer, Length);
}

View File

@ -16,12 +16,16 @@
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = MemoryAllocationLib|HOST_APPLICATION
LIBRARY_CLASS = HostMemoryAllocationBelowAddressLib|HOST_APPLICATION
[Sources]
MemoryAllocationLibPosix.c
AllocateBelowAddress.c
WinInclude.h
[Packages]
MdePkg/MdePkg.dec
UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
[LibraryClasses]
BaseLib
DebugLib

View File

@ -0,0 +1,28 @@
/** @file
Include windows.h addressing conflicts with forced include of Base.h
Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef WIN_INCLUDE_H_
#define WIN_INCLUDE_H_
#define GUID _WINNT_DUP_GUID_____
#define _LIST_ENTRY _WINNT_DUP_LIST_ENTRY_FORWARD
#define LIST_ENTRY _WINNT_DUP_LIST_ENTRY
#undef VOID
#pragma warning (push)
#pragma warning (disable : 4668)
#include <windows.h>
#pragma warning (pop)
#undef GUID
#undef _LIST_ENTRY
#undef LIST_ENTRY
#define VOID void
#endif

View File

@ -13,6 +13,7 @@ extern "C" {
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/HostMemoryAllocationBelowAddressLib.h>
}
/**
@ -433,6 +434,215 @@ TEST (SanitizerTests, DivideByZeroDeathTest) {
EXPECT_DEATH (DivideWithNoParameterChecking (10, 0), "ERROR: AddressSanitizer: ");
}
/**
Sample unit test that allocates and frees buffers below 4GB
**/
TEST (MemoryAllocationTests, Below4GB) {
VOID *Buffer1;
VOID *Buffer2;
UINT8 EmptyBuffer[0x100];
//
// Length 0 always fails
//
Buffer1 = HostAllocatePoolBelowAddress (BASE_4GB - 1, 0);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Length == Maximum Address always fails
//
Buffer1 = HostAllocatePoolBelowAddress (BASE_4GB - 1, SIZE_4GB);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Length > Maximum Address always fails
//
Buffer1 = HostAllocatePoolBelowAddress (BASE_4GB - 1, SIZE_8GB);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Maximum Address 0 always fails
//
Buffer1 = HostAllocatePoolBelowAddress (0, SIZE_4KB);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Maximum Address < 64KB always fails
//
Buffer1 = HostAllocatePoolBelowAddress (BASE_64KB - 1, SIZE_4KB);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Not enough memory available always fails
//
Buffer1 = HostAllocatePoolBelowAddress (BASE_128KB - 1, SIZE_64KB);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Allocation of 4KB buffer below 4GB must succeed
//
Buffer1 = HostAllocatePoolBelowAddress (BASE_4GB - 1, SIZE_4KB);
ASSERT_NE (Buffer1, (VOID *)NULL);
ASSERT_LT ((UINTN)Buffer1, BASE_4GB);
//
// Allocated buffer must support read and write
//
*(UINT8 *)Buffer1 = 0x5A;
ASSERT_EQ (*(UINT8 *)Buffer1, 0x5A);
//
// Allocation of 1MB buffer below 4GB must succeed
//
Buffer2 = HostAllocatePoolBelowAddress (BASE_4GB - 1, SIZE_1MB);
ASSERT_NE (Buffer2, (VOID *)NULL);
ASSERT_LT ((UINTN)Buffer2, BASE_4GB);
//
// Allocated buffer must support read and write
//
*(UINT8 *)Buffer2 = 0x5A;
ASSERT_EQ (*(UINT8 *)Buffer2, 0x5A);
//
// Allocations must return different values
//
ASSERT_NE (Buffer1, Buffer2);
//
// Free buffers below 4GB must not ASSERT
//
HostFreePoolBelowAddress (Buffer1);
HostFreePoolBelowAddress (Buffer2);
//
// Expect ASSERT() tests
//
EXPECT_ANY_THROW (HostFreePoolBelowAddress (NULL));
EXPECT_ANY_THROW (HostFreePoolBelowAddress (EmptyBuffer + 0x80));
Buffer1 = AllocatePool (0x100);
EXPECT_ANY_THROW (HostFreePoolBelowAddress ((UINT8 *)Buffer1 + 0x80));
FreePool (Buffer1);
}
/**
Sample unit test that allocates and frees aligned pages below 4GB
**/
TEST (MemoryAllocationTests, AlignedBelow4GB) {
VOID *Buffer1;
VOID *Buffer2;
UINT8 EmptyBuffer[0x100];
//
// Pages 0 always fails
//
Buffer1 = HostAllocateAlignedPagesBelowAddress (BASE_4GB - 1, 0, SIZE_4KB);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Alignment not a power of 2 always fails
//
Buffer1 = HostAllocateAlignedPagesBelowAddress (BASE_4GB - 1, SIZE_4KB, 5);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Alignment not a power of 2 always fails
//
Buffer1 = HostAllocateAlignedPagesBelowAddress (BASE_4GB - 1, SIZE_4KB, SIZE_16KB + 1);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Alignment larger than largest supported virtual address always fails
// Only applies to 32-bit architectures
//
if (sizeof (UINTN) == sizeof (UINT32)) {
Buffer1 = HostAllocateAlignedPagesBelowAddress (BASE_4GB - 1, SIZE_4KB, SIZE_4GB);
ASSERT_EQ (Buffer1, (VOID *)NULL);
}
//
// Length == Maximum Address always fails
//
Buffer1 = HostAllocateAlignedPagesBelowAddress (BASE_4GB - 1, EFI_SIZE_TO_PAGES (SIZE_4GB), SIZE_4KB);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Length > Maximum Address always fails
//
Buffer1 = HostAllocateAlignedPagesBelowAddress (BASE_4GB - 1, EFI_SIZE_TO_PAGES (SIZE_8GB), SIZE_4KB);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Alignment >= Maximum Address always fails
//
Buffer1 = HostAllocateAlignedPagesBelowAddress (BASE_4GB - 1, EFI_SIZE_TO_PAGES (SIZE_4GB), SIZE_4GB);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Maximum Address 0 always fails
//
Buffer1 = HostAllocateAlignedPagesBelowAddress (0, EFI_SIZE_TO_PAGES (SIZE_4KB), SIZE_4KB);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Maximum Address <= 64KB always fails
//
Buffer1 = HostAllocateAlignedPagesBelowAddress (BASE_64KB - 1, EFI_SIZE_TO_PAGES (SIZE_4KB), SIZE_4KB);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Not enough memory available always fails
//
Buffer1 = HostAllocateAlignedPagesBelowAddress (BASE_128KB - 1, EFI_SIZE_TO_PAGES (SIZE_64KB), SIZE_4KB);
ASSERT_EQ (Buffer1, (VOID *)NULL);
//
// Allocation of 4KB buffer below 4GB must succeed
//
Buffer1 = HostAllocateAlignedPagesBelowAddress (BASE_4GB - 1, EFI_SIZE_TO_PAGES (SIZE_4KB), SIZE_4KB);
ASSERT_NE (Buffer1, (VOID *)NULL);
ASSERT_LT ((UINTN)Buffer1, BASE_4GB);
//
// Allocated buffer must support read and write
//
*(UINT8 *)Buffer1 = 0x5A;
ASSERT_EQ (*(UINT8 *)Buffer1, 0x5A);
//
// Allocation of 1MB buffer below 4GB must succeed
//
Buffer2 = HostAllocateAlignedPagesBelowAddress (BASE_4GB - 1, EFI_SIZE_TO_PAGES (SIZE_1MB), SIZE_1MB);
ASSERT_NE (Buffer2, (VOID *)NULL);
ASSERT_LT ((UINTN)Buffer2, BASE_4GB);
//
// Allocated buffer must support read and write
//
*(UINT8 *)Buffer2 = 0x5A;
ASSERT_EQ (*(UINT8 *)Buffer2, 0x5A);
//
// Allocations must return different values
//
ASSERT_NE (Buffer1, Buffer2);
//
// Free buffers below 4GB must not ASSERT
//
HostFreeAlignedPagesBelowAddress (Buffer1, EFI_SIZE_TO_PAGES (SIZE_4KB));
HostFreeAlignedPagesBelowAddress (Buffer2, EFI_SIZE_TO_PAGES (SIZE_1MB));
//
// Expect ASSERT() tests
//
EXPECT_ANY_THROW (HostFreeAlignedPagesBelowAddress (NULL, 0));
EXPECT_ANY_THROW (HostFreeAlignedPagesBelowAddress (EmptyBuffer + 0x80, 1));
Buffer1 = AllocatePool (0x100);
EXPECT_ANY_THROW (HostFreeAlignedPagesBelowAddress ((UINT8 *)Buffer1 + 0x80, 1));
FreePool (Buffer1);
}
int
main (
int argc,

View File

@ -96,6 +96,7 @@
"Library/SubhookLib/subhook/**/*.*" # not going to spell check a submodule
],
"ExtendWords": [ # words to extend to the dictionary for this package
"noreplace",
"Pointee",
"gmock",
"GMOCK",

View File

@ -39,6 +39,11 @@
SubhookLib|Include/Library/SubhookLib.h
FunctionMockLib|Include/Library/FunctionMockLib.h
## @libraryclass Host only memory allocation library that supports allocating
# buffers below a specified address.
#
HostMemoryAllocationBelowAddressLib|Include/Library/HostMemoryAllocationBelowAddressLib.h
[LibraryClasses.Common.Private]
## @libraryclass Provides a unit test result report
#

View File

@ -23,6 +23,7 @@
UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf
DebugLib|UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf
MemoryAllocationLib|UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf
HostMemoryAllocationBelowAddressLib|UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf
UefiBootServicesTableLib|UnitTestFrameworkPkg/Library/UnitTestUefiBootServicesTableLib/UnitTestUefiBootServicesTableLib.inf
PeiServicesTablePointerLib|UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.inf
NULL|UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLibHost.inf