X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=CryptoPkg%2FLibrary%2FBaseCryptLib%2FSysCall%2FRuntimeMemAllocation.c;fp=CryptoPkg%2FLibrary%2FBaseCryptLib%2FSysCall%2FRuntimeMemAllocation.c;h=f615ae8f903c3efabff99831b6bf3eb17dd047ee;hp=0000000000000000000000000000000000000000;hb=97f98500c1d40eba76210961e90ea5d354bcbc18;hpb=a3bcde70e6dc69000f85cc5deee98101d2ae200a diff --git a/CryptoPkg/Library/BaseCryptLib/SysCall/RuntimeMemAllocation.c b/CryptoPkg/Library/BaseCryptLib/SysCall/RuntimeMemAllocation.c new file mode 100644 index 0000000000..f615ae8f90 --- /dev/null +++ b/CryptoPkg/Library/BaseCryptLib/SysCall/RuntimeMemAllocation.c @@ -0,0 +1,438 @@ +/** @file + Light-weight Memory Management Routines for OpenSSL-based Crypto + Library at Runtime Phase. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include + +//---------------------------------------------------------------- +// Initial version. Needs further optimizations. +//---------------------------------------------------------------- + +// +// Definitions for Runtime Memory Operations +// +#define RT_PAGE_SIZE 0x200 +#define RT_PAGE_MASK 0x1FF +#define RT_PAGE_SHIFT 9 + +#define RT_SIZE_TO_PAGES(a) (((a) >> RT_PAGE_SHIFT) + (((a) & RT_PAGE_MASK) ? 1 : 0)) +#define RT_PAGES_TO_SIZE(a) ((a) << RT_PAGE_SHIFT) + +// +// Page Flag Definitions +// +#define RT_PAGE_FREE 0x00000000 +#define RT_PAGE_USED 0x00000001 + +#define MIN_REQUIRED_BLOCKS 24 + +// +// Memory Page Table +// +typedef struct { + UINTN StartPageOffset; // Offset of the starting page allocated. + // Only available for USED pages. + UINT32 PageFlag; // Page Attributes. +} RT_MEMORY_PAGE_ENTRY; + +typedef struct { + UINTN PageCount; + UINTN LastEmptyPageOffset; + UINT8 *DataAreaBase; // Pointer to data Area. + RT_MEMORY_PAGE_ENTRY Pages[1]; // Page Table Entries. +} RT_MEMORY_PAGE_TABLE; + +// +// Global Page Table for Runtime Cryptographic Provider. +// +RT_MEMORY_PAGE_TABLE *mRTPageTable = NULL; + +// +// Event for Runtime Address Conversion. +// +EFI_EVENT mVirtualAddressChangeEvent; + + +/** + Initializes pre-allocated memory pointed by ScratchBuffer for subsequent + runtime use. + + @param[in, out] ScratchBuffer Pointer to user-supplied memory buffer. + @param[in] ScratchBufferSize Size of supplied buffer in bytes. + + @retval EFI_SUCCESS Successful initialization. + +**/ +EFI_STATUS +InitializeScratchMemory ( + IN OUT UINT8 *ScratchBuffer, + IN UINTN ScratchBufferSize + ) +{ + UINTN Index; + UINTN MemorySize; + + // + // Parameters Checking + // + if (ScratchBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (ScratchBufferSize < MIN_REQUIRED_BLOCKS * 1024) { + return EFI_BUFFER_TOO_SMALL; + } + + mRTPageTable = (RT_MEMORY_PAGE_TABLE *)ScratchBuffer; + + // + // Initialize Internal Page Table for Memory Management + // + SetMem (mRTPageTable, ScratchBufferSize, 0xFF); + MemorySize = ScratchBufferSize - sizeof (RT_MEMORY_PAGE_TABLE) + sizeof (RT_MEMORY_PAGE_ENTRY); + + mRTPageTable->PageCount = MemorySize / (RT_PAGE_SIZE + sizeof (RT_MEMORY_PAGE_ENTRY)); + mRTPageTable->LastEmptyPageOffset = 0x0; + + for (Index = 0; Index < mRTPageTable->PageCount; Index++) { + mRTPageTable->Pages[Index].PageFlag = RT_PAGE_FREE; + mRTPageTable->Pages[Index].StartPageOffset = 0; + } + + mRTPageTable->DataAreaBase = ScratchBuffer + sizeof (RT_MEMORY_PAGE_TABLE) + + (mRTPageTable->PageCount - 1) * sizeof (RT_MEMORY_PAGE_ENTRY); + + return EFI_SUCCESS; +} + + +/** + Look-up Free memory Region for object allocation. + + @param[in] AllocationSize Bytes to be allocated. + + @return Return available page offset for object allocation. + +**/ +UINTN +LookupFreeMemRegion ( + IN UINTN AllocationSize + ) +{ + UINTN StartPageIndex; + UINTN Index; + UINTN SubIndex; + UINTN ReqPages; + + StartPageIndex = RT_SIZE_TO_PAGES (mRTPageTable->LastEmptyPageOffset); + ReqPages = RT_SIZE_TO_PAGES (AllocationSize); + + // + // Look up the free memory region with in current memory map table. + // + for (Index = StartPageIndex; Index <= (mRTPageTable->PageCount - ReqPages); ) { + // + // Check consecutive ReqPages pages. + // + for (SubIndex = 0; SubIndex < ReqPages; SubIndex++) { + if ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0) { + break; + } + } + + if (SubIndex == ReqPages) { + // + // Succeed! Return the Starting Offset. + // + return RT_PAGES_TO_SIZE (Index); + } + + // + // Failed! Skip current free memory pages and adjacent Used pages + // + while ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0) { + SubIndex++; + } + + Index += SubIndex; + } + + // + // Look up the free memory region from the beginning of the memory table + // until the StartCursorOffset + // + for (Index = 0; Index < (StartPageIndex - ReqPages); ) { + // + // Check Consecutive ReqPages Pages. + // + for (SubIndex = 0; SubIndex < ReqPages; SubIndex++) { + if ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0) { + break; + } + } + + if (SubIndex == ReqPages) { + // + // Succeed! Return the Starting Offset. + // + return RT_PAGES_TO_SIZE (Index); + } + + // + // Failed! Skip current adjacent Used pages + // + while ((SubIndex < (StartPageIndex - ReqPages)) && + ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0)) { + SubIndex++; + } + + Index += SubIndex; + } + + // + // No availabe region for object allocation! + // + return (UINTN)(-1); +} + + +/** + Allocates a buffer at runtime phase. + + @param[in] AllocationSize Bytes to be allocated. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +RuntimeAllocateMem ( + IN UINTN AllocationSize + ) +{ + UINT8 *AllocPtr; + UINTN ReqPages; + UINTN Index; + UINTN StartPage; + UINTN AllocOffset; + + AllocPtr = NULL; + ReqPages = 0; + + // + // Look for available consecutive memory region starting from LastEmptyPageOffset. + // If no proper memory region found, look up from the beginning. + // If still not found, return NULL to indicate failed allocation. + // + AllocOffset = LookupFreeMemRegion (AllocationSize); + if (AllocOffset == (UINTN)(-1)) { + return NULL; + } + + // + // Allocates consecutive memory pages with length of Size. Update the page + // table status. Returns the starting address. + // + ReqPages = RT_SIZE_TO_PAGES (AllocationSize); + AllocPtr = mRTPageTable->DataAreaBase + AllocOffset; + StartPage = RT_SIZE_TO_PAGES (AllocOffset); + Index = 0; + while (Index < ReqPages) { + mRTPageTable->Pages[StartPage + Index].PageFlag |= RT_PAGE_USED; + mRTPageTable->Pages[StartPage + Index].StartPageOffset = AllocOffset; + + Index++; + } + + mRTPageTable->LastEmptyPageOffset = AllocOffset + RT_PAGES_TO_SIZE (ReqPages); + + ZeroMem (AllocPtr, AllocationSize); + + // + // Returns a void pointer to the allocated space + // + return AllocPtr; +} + + +/** + Frees a buffer that was previously allocated at runtime phase. + + @param[in] Buffer Pointer to the buffer to free. + +**/ +VOID +RuntimeFreeMem ( + IN VOID *Buffer + ) +{ + UINTN StartOffset; + UINTN StartPageIndex; + + StartOffset = (UINTN) ((UINT8 *)Buffer - mRTPageTable->DataAreaBase); + StartPageIndex = RT_SIZE_TO_PAGES (mRTPageTable->Pages[RT_SIZE_TO_PAGES(StartOffset)].StartPageOffset); + + while (StartPageIndex < mRTPageTable->PageCount) { + if (((mRTPageTable->Pages[StartPageIndex].PageFlag & RT_PAGE_USED) != 0) && + (mRTPageTable->Pages[StartPageIndex].StartPageOffset == StartOffset)) { + // + // Free this page + // + mRTPageTable->Pages[StartPageIndex].PageFlag &= ~RT_PAGE_USED; + mRTPageTable->Pages[StartPageIndex].PageFlag |= RT_PAGE_FREE; + mRTPageTable->Pages[StartPageIndex].StartPageOffset = 0; + + StartPageIndex++; + } else { + break; + } + } + + return; +} + + +/** + Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. + + This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE + event. It converts a pointer to a new virtual address. + + @param[in] Event The event whose notification function is being invoked. + @param[in] Context The pointer to the notification function's context. + +**/ +VOID +EFIAPI +RuntimeCryptLibAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Converts a pointer for runtime memory management to a new virtual address. + // + EfiConvertPointer (0x0, (VOID **) &mRTPageTable->DataAreaBase); + EfiConvertPointer (0x0, (VOID **) &mRTPageTable); +} + + +/** + Constructor routine for runtime crypt library instance. + + The constructor function pre-allocates space for runtime cryptographic operation. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The construction succeeded. + @retval EFI_OUT_OF_RESOURCE Failed to allocate memory. + +**/ +EFI_STATUS +EFIAPI +RuntimeCryptLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + VOID *Buffer; + + // + // Pre-allocates runtime space for possible cryptographic operations + // + Buffer = AllocateRuntimePool (MIN_REQUIRED_BLOCKS * 1024); + Status = InitializeScratchMemory (Buffer, MIN_REQUIRED_BLOCKS * 1024); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Create address change event + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + RuntimeCryptLibAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mVirtualAddressChangeEvent + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + + +// +// -- Memory-Allocation Routines Wrapper for UEFI-OpenSSL Library -- +// + +/* Allocates memory blocks */ +void *malloc (size_t size) +{ + return RuntimeAllocateMem ((UINTN)size); +} + +/* Reallocate memory blocks */ +void *realloc (void *ptr, size_t size) +{ + VOID *NewPtr; + UINTN StartOffset; + UINTN StartPageIndex; + UINTN PageCount; + + // + // Get Original Size of ptr + // + StartOffset = (UINTN) ((UINT8 *)ptr - mRTPageTable->DataAreaBase); + StartPageIndex = RT_SIZE_TO_PAGES (mRTPageTable->Pages[RT_SIZE_TO_PAGES (StartOffset)].StartPageOffset); + PageCount = 0; + while (StartPageIndex < mRTPageTable->PageCount) { + if (((mRTPageTable->Pages[StartPageIndex].PageFlag & RT_PAGE_USED) != 0) && + (mRTPageTable->Pages[StartPageIndex].StartPageOffset == StartOffset)) { + StartPageIndex++; + PageCount++; + } else { + break; + } + } + + if (size <= RT_PAGES_TO_SIZE (PageCount)) { + // + // Return the original pointer, if Caller try to reduce region size; + // + return ptr; + } + + NewPtr = RuntimeAllocateMem ((UINTN) size); + if (NewPtr == NULL) { + return NULL; + } + + CopyMem (NewPtr, ptr, RT_PAGES_TO_SIZE (PageCount)); + + RuntimeFreeMem (ptr); + + return NewPtr; +} + +/* Deallocates or frees a memory block */ +void free (void *ptr) +{ + RuntimeFreeMem (ptr); +}