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