mirror of
https://github.com/acidanthera/audk.git
synced 2025-07-23 13:44:33 +02:00
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:
parent
5f97d5391e
commit
e78fb8a366
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user