mirror of
https://github.com/acidanthera/audk.git
synced 2025-07-26 15:14:02 +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
|
MODULE_TYPE = UEFI_DRIVER
|
||||||
VERSION_STRING = 1.0
|
VERSION_STRING = 1.0
|
||||||
LIBRARY_CLASS = MemoryAllocationLib|HOST_APPLICATION
|
LIBRARY_CLASS = MemoryAllocationLib|HOST_APPLICATION
|
||||||
|
LIBRARY_CLASS = HostMemoryAllocationBelowAddressLib|HOST_APPLICATION
|
||||||
|
|
||||||
[Sources]
|
[Sources]
|
||||||
MemoryAllocationLibPosix.c
|
MemoryAllocationLibPosix.c
|
||||||
|
AllocateBelowAddress.c
|
||||||
|
WinInclude.h
|
||||||
|
|
||||||
[Packages]
|
[Packages]
|
||||||
MdePkg/MdePkg.dec
|
MdePkg/MdePkg.dec
|
||||||
|
UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
|
||||||
|
|
||||||
[LibraryClasses]
|
[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/BaseLib.h>
|
||||||
#include <Library/DebugLib.h>
|
#include <Library/DebugLib.h>
|
||||||
#include <Library/MemoryAllocationLib.h>
|
#include <Library/MemoryAllocationLib.h>
|
||||||
|
#include <Library/HostMemoryAllocationBelowAddressLib.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -433,6 +434,215 @@ TEST (SanitizerTests, DivideByZeroDeathTest) {
|
|||||||
EXPECT_DEATH (DivideWithNoParameterChecking (10, 0), "ERROR: AddressSanitizer: ");
|
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
|
int
|
||||||
main (
|
main (
|
||||||
int argc,
|
int argc,
|
||||||
|
@ -96,6 +96,7 @@
|
|||||||
"Library/SubhookLib/subhook/**/*.*" # not going to spell check a submodule
|
"Library/SubhookLib/subhook/**/*.*" # not going to spell check a submodule
|
||||||
],
|
],
|
||||||
"ExtendWords": [ # words to extend to the dictionary for this package
|
"ExtendWords": [ # words to extend to the dictionary for this package
|
||||||
|
"noreplace",
|
||||||
"Pointee",
|
"Pointee",
|
||||||
"gmock",
|
"gmock",
|
||||||
"GMOCK",
|
"GMOCK",
|
||||||
|
@ -39,6 +39,11 @@
|
|||||||
SubhookLib|Include/Library/SubhookLib.h
|
SubhookLib|Include/Library/SubhookLib.h
|
||||||
FunctionMockLib|Include/Library/FunctionMockLib.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]
|
[LibraryClasses.Common.Private]
|
||||||
## @libraryclass Provides a unit test result report
|
## @libraryclass Provides a unit test result report
|
||||||
#
|
#
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf
|
UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf
|
||||||
DebugLib|UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf
|
DebugLib|UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf
|
||||||
MemoryAllocationLib|UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf
|
MemoryAllocationLib|UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf
|
||||||
|
HostMemoryAllocationBelowAddressLib|UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf
|
||||||
UefiBootServicesTableLib|UnitTestFrameworkPkg/Library/UnitTestUefiBootServicesTableLib/UnitTestUefiBootServicesTableLib.inf
|
UefiBootServicesTableLib|UnitTestFrameworkPkg/Library/UnitTestUefiBootServicesTableLib/UnitTestUefiBootServicesTableLib.inf
|
||||||
PeiServicesTablePointerLib|UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.inf
|
PeiServicesTablePointerLib|UnitTestFrameworkPkg/Library/UnitTestPeiServicesTablePointerLib/UnitTestPeiServicesTablePointerLib.inf
|
||||||
NULL|UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLibHost.inf
|
NULL|UnitTestFrameworkPkg/Library/UnitTestDebugAssertLib/UnitTestDebugAssertLibHost.inf
|
||||||
|
Loading…
x
Reference in New Issue
Block a user