diff --git a/UnitTestFrameworkPkg/Include/Library/HostMemoryAllocationBelowAddressLib.h b/UnitTestFrameworkPkg/Include/Library/HostMemoryAllocationBelowAddressLib.h new file mode 100644 index 0000000000000..38bba3f48fa95 --- /dev/null +++ b/UnitTestFrameworkPkg/Include/Library/HostMemoryAllocationBelowAddressLib.h @@ -0,0 +1,93 @@ +/** @file + HostMemoryAllocationBelowAddressLib class + + Copyright (c) 2024, Intel Corporation. All rights reserved.
+ 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 VOID *MaximumAddress, + IN UINTN Length + ); + +/** + Free memory allocated with AllocateMemoryHostAllocatePoolBelowAddress(). + + @param[in] Address Pointer to buffer previously allocated with + HostAllocatePoolBelowAddress(). + + @retval TRUE The buffer was freed. + @retval FALSE The buffer could not be freed.. +**/ +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 VOID *MaximumAddress, + IN UINTN Pages, + IN UINTN 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 diff --git a/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/AllocateBelowAddress.c b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/AllocateBelowAddress.c new file mode 100644 index 0000000000000..bb00000de0388 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/AllocateBelowAddress.c @@ -0,0 +1,382 @@ +/** @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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#if defined (_WIN32) || defined (_WIN64) + #include "WinInclude.h" +#elif defined (__linux__) + #include + #include + #include + #include +#else + #error Unsupported target +#endif + +#include +#include + +/// +/// 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_32 ('P', 'A', 'B', 'E') + +/// +/// Structure placed immediately before an aligned allocation to store the +/// information required to free the entire allocated buffer. +/// +typedef struct { + UINT32 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_32 ('P', 'H', 'D', 'B') + +/// +/// Structure placed immediately before an pool allocation to store the +/// information required to free the entire allocated buffer. +/// +typedef struct { + UINT32 Signature; + UINT32 TotalSize; +} POOL_HEAD_BELOW_ADDRESS; + +// +// 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] MinimumAddress The address above which the memory allocation must + be performed. + @param[in] Length The size, in bytes, of the memory allocation. + @param[in] PageSize The page size to which the memory allocation must + be aligned. + + @retval !NULL Pointer to the allocated memory. + @retval NULL The memory allocation failed. +**/ +static +VOID * +HostAllocateBufferInRange ( + UINTN MaximumAddress, + UINTN MinimumAddress, + UINTN Length, + UINTN PageSize + ) +{ + UINTN Address; + VOID *AllocatedAddress; + + for (Address = MaximumAddress; Address >= MinimumAddress; Address -= PageSize) { + #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 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 VOID *MaximumAddress, + IN UINTN Length + ) +{ + VOID *AllocatedAddress; + POOL_HEAD_BELOW_ADDRESS *PoolHead; + + if (mPageSize == 0) { + mPageSize = HostGetPageSize (); + if (mPageSize == 0) { + return NULL; + } + } + + if ((Length == 0) || (Length >= (UINTN)MaximumAddress)) { + return NULL; + } + + Length += sizeof (POOL_HEAD_BELOW_ADDRESS); + + AllocatedAddress = HostAllocateBufferInRange ( + ((UINTN)MaximumAddress - Length) & ~(mPageSize - 1), + BASE_64KB, + Length, + mPageSize + ); + if (AllocatedAddress == NULL) { + return NULL; + } + + DEBUG_CLEAR_MEMORY (AllocatedAddress, Length); + PoolHead = (POOL_HEAD_BELOW_ADDRESS *)AllocatedAddress; + PoolHead->Signature = POOL_HEAD_BELOW_ADDRESS_PRIVATE_SIGNATURE; + PoolHead->TotalSize = (UINT32)(Length); + return (VOID *)(PoolHead + 1); +} + +/** + Free memory allocated with HostAllocatePoolBelowAddress(). + + @param[in] Buffer Pointer to buffer previously allocated with + HostAllocatePoolBelowAddress(). + + @retval TRUE The buffer was freed. + @retval FALSE The buffer could not be freed.. +**/ +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)); + + Length = 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 VOID *MaximumAddress, + IN UINTN Pages, + IN UINTN Alignment + ) +{ + PAGE_HEAD_BELOW_ADDRESS PageHead; + PAGE_HEAD_BELOW_ADDRESS *PageHeadPtr; + UINTN AlignmentMask; + + if (mPageSize == 0) { + mPageSize = HostGetPageSize (); + if (mPageSize == 0) { + return NULL; + } + } + + if ((Pages == 0) || (EFI_PAGES_TO_SIZE (Pages) >= (UINTN)MaximumAddress)) { + return NULL; + } + + ASSERT ((Alignment & (Alignment - 1)) == 0); + + if (Alignment < SIZE_4KB) { + Alignment = SIZE_4KB; + } + + AlignmentMask = Alignment - 1; + + // + // We need reserve Alignment pages for PAGE_HEAD_BELOW_ADDRESS, as meta data. + // + PageHead.Signature = PAGE_HEAD_BELOW_ADDRESS_PRIVATE_SIGNATURE; + PageHead.TotalPages = Pages + EFI_SIZE_TO_PAGES (Alignment) * 2; + PageHead.AlignedPages = Pages; + PageHead.AllocatedBuffer = HostAllocateBufferInRange ( + ((UINTN)MaximumAddress - EFI_PAGES_TO_SIZE (PageHead.TotalPages)) & ~(mPageSize - 1), + BASE_64KB, + EFI_PAGES_TO_SIZE (PageHead.TotalPages), + mPageSize + ); + if (PageHead.AllocatedBuffer == NULL) { + return NULL; + } + + DEBUG_CLEAR_MEMORY (PageHead.AllocatedBuffer, EFI_PAGES_TO_SIZE (PageHead.TotalPages)); + + 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 + Alignment); + } + + PageHeadPtr = (VOID *)((UINTN)PageHead.AlignedBuffer - sizeof (PAGE_HEAD_BELOW_ADDRESS)); + memcpy (PageHeadPtr, &PageHead, sizeof (PAGE_HEAD_BELOW_ADDRESS)); + + 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); +} diff --git a/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf index 44ec3fd517222..1443600013e22 100644 --- a/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf +++ b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf @@ -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 diff --git a/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/WinInclude.h b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/WinInclude.h new file mode 100644 index 0000000000000..1197018282c40 --- /dev/null +++ b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/WinInclude.h @@ -0,0 +1,23 @@ +/** @file + Include windows.h addressing conflicts with forced include of Base.h + + Copyright (c) 2024, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#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 + +#pragma warning (pop) + +#undef GUID +#undef _LIST_ENTRY +#undef LIST_ENTRY +#define VOID void diff --git a/UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/SampleGoogleTest.cpp b/UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/SampleGoogleTest.cpp index f3643dc864dea..d435ba411e9fc 100644 --- a/UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/SampleGoogleTest.cpp +++ b/UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/SampleGoogleTest.cpp @@ -13,6 +13,7 @@ extern "C" { #include #include #include + #include } /** @@ -433,6 +434,176 @@ 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 ((VOID *)BASE_4GB, 0); + ASSERT_EQ (Buffer1, (VOID *)NULL); + + // + // Length == Maximum Address always fails + // + Buffer1 = HostAllocatePoolBelowAddress ((VOID *)BASE_4GB, SIZE_4GB); + ASSERT_EQ (Buffer1, (VOID *)NULL); + + // + // Length > Maximum Address always fails + // + Buffer1 = HostAllocatePoolBelowAddress ((VOID *)BASE_4GB, SIZE_8GB); + ASSERT_EQ (Buffer1, (VOID *)NULL); + + // + // Maximum Address <= 64KB always fails + // + Buffer1 = HostAllocatePoolBelowAddress ((VOID *)NULL, SIZE_4KB); + ASSERT_EQ (Buffer1, (VOID *)NULL); + + // + // Maximum Address <= 64KB always fails + // + Buffer1 = HostAllocatePoolBelowAddress ((VOID *)BASE_64KB, SIZE_4KB); + ASSERT_EQ (Buffer1, (VOID *)NULL); + + // + // Allocation of 4KB buffer below 4GB must succeed + // + Buffer1 = HostAllocatePoolBelowAddress ((VOID *)BASE_4GB, 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 ((VOID *)BASE_4GB, 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 (Buffer1)); + 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 ((VOID *)BASE_4GB, 0, SIZE_4KB); + ASSERT_EQ (Buffer1, (VOID *)NULL); + + // + // Length == Maximum Address always fails + // + Buffer1 = HostAllocateAlignedPagesBelowAddress ((VOID *)BASE_4GB, EFI_SIZE_TO_PAGES (SIZE_4GB), SIZE_4KB); + ASSERT_EQ (Buffer1, (VOID *)NULL); + + // + // Length > Maximum Address always fails + // + Buffer1 = HostAllocateAlignedPagesBelowAddress ((VOID *)BASE_4GB, EFI_SIZE_TO_PAGES (SIZE_8GB), SIZE_4KB); + ASSERT_EQ (Buffer1, (VOID *)NULL); + + // + // Maximum Address <= 64KB always fails + // + Buffer1 = HostAllocateAlignedPagesBelowAddress ((VOID *)NULL, EFI_SIZE_TO_PAGES (SIZE_4KB), SIZE_4KB); + ASSERT_EQ (Buffer1, (VOID *)NULL); + + // + // Maximum Address <= 64KB always fails + // + Buffer1 = HostAllocateAlignedPagesBelowAddress ((VOID *)BASE_64KB, EFI_SIZE_TO_PAGES (SIZE_4KB), SIZE_4KB); + ASSERT_EQ (Buffer1, (VOID *)NULL); + + // + // Allocation of 4KB buffer below 4GB must succeed + // + Buffer1 = HostAllocateAlignedPagesBelowAddress ((VOID *)BASE_4GB, 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 ((VOID *)BASE_4GB, 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, diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.ci.yaml b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.ci.yaml index cf51b21e00d45..970ba900b820a 100644 --- a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.ci.yaml +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.ci.yaml @@ -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", diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec index ef0a148d48764..0553af4edc370 100644 --- a/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec @@ -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 # diff --git a/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc b/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc index f7cd035adce3e..2e6b0d28c69ac 100644 --- a/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc +++ b/UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc @@ -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