2 Light-weight Memory Management Routines for OpenSSL-based Crypto
3 Library at Runtime Phase.
5 Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <CrtLibSupport.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/UefiRuntimeLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Guid/EventGroup.h>
22 //----------------------------------------------------------------
23 // Initial version. Needs further optimizations.
24 //----------------------------------------------------------------
27 // Definitions for Runtime Memory Operations
29 #define RT_PAGE_SIZE 0x200
30 #define RT_PAGE_MASK 0x1FF
31 #define RT_PAGE_SHIFT 9
33 #define RT_SIZE_TO_PAGES(a) (((a) >> RT_PAGE_SHIFT) + (((a) & RT_PAGE_MASK) ? 1 : 0))
34 #define RT_PAGES_TO_SIZE(a) ((a) << RT_PAGE_SHIFT)
37 // Page Flag Definitions
39 #define RT_PAGE_FREE 0x00000000
40 #define RT_PAGE_USED 0x00000001
42 #define MIN_REQUIRED_BLOCKS 600
48 UINTN StartPageOffset
; // Offset of the starting page allocated.
49 // Only available for USED pages.
50 UINT32 PageFlag
; // Page Attributes.
51 } RT_MEMORY_PAGE_ENTRY
;
55 UINTN LastEmptyPageOffset
;
56 UINT8
*DataAreaBase
; // Pointer to data Area.
57 RT_MEMORY_PAGE_ENTRY Pages
[1]; // Page Table Entries.
58 } RT_MEMORY_PAGE_TABLE
;
61 // Global Page Table for Runtime Cryptographic Provider.
63 RT_MEMORY_PAGE_TABLE
*mRTPageTable
= NULL
;
66 // Event for Runtime Address Conversion.
68 STATIC EFI_EVENT mVirtualAddressChangeEvent
;
72 Initializes pre-allocated memory pointed by ScratchBuffer for subsequent
75 @param[in, out] ScratchBuffer Pointer to user-supplied memory buffer.
76 @param[in] ScratchBufferSize Size of supplied buffer in bytes.
78 @retval EFI_SUCCESS Successful initialization.
82 InitializeScratchMemory (
83 IN OUT UINT8
*ScratchBuffer
,
84 IN UINTN ScratchBufferSize
91 // Parameters Checking
93 if (ScratchBuffer
== NULL
) {
94 return EFI_INVALID_PARAMETER
;
97 if (ScratchBufferSize
< MIN_REQUIRED_BLOCKS
* 1024) {
98 return EFI_BUFFER_TOO_SMALL
;
101 mRTPageTable
= (RT_MEMORY_PAGE_TABLE
*)ScratchBuffer
;
104 // Initialize Internal Page Table for Memory Management
106 SetMem (mRTPageTable
, ScratchBufferSize
, 0xFF);
107 MemorySize
= ScratchBufferSize
- sizeof (RT_MEMORY_PAGE_TABLE
) + sizeof (RT_MEMORY_PAGE_ENTRY
);
109 mRTPageTable
->PageCount
= MemorySize
/ (RT_PAGE_SIZE
+ sizeof (RT_MEMORY_PAGE_ENTRY
));
110 mRTPageTable
->LastEmptyPageOffset
= 0x0;
112 for (Index
= 0; Index
< mRTPageTable
->PageCount
; Index
++) {
113 mRTPageTable
->Pages
[Index
].PageFlag
= RT_PAGE_FREE
;
114 mRTPageTable
->Pages
[Index
].StartPageOffset
= 0;
117 mRTPageTable
->DataAreaBase
= ScratchBuffer
+ sizeof (RT_MEMORY_PAGE_TABLE
) +
118 (mRTPageTable
->PageCount
- 1) * sizeof (RT_MEMORY_PAGE_ENTRY
);
125 Look-up Free memory Region for object allocation.
127 @param[in] AllocationSize Bytes to be allocated.
129 @return Return available page offset for object allocation.
133 LookupFreeMemRegion (
134 IN UINTN AllocationSize
137 UINTN StartPageIndex
;
142 StartPageIndex
= RT_SIZE_TO_PAGES (mRTPageTable
->LastEmptyPageOffset
);
143 ReqPages
= RT_SIZE_TO_PAGES (AllocationSize
);
146 // Look up the free memory region with in current memory map table.
148 for (Index
= StartPageIndex
; Index
<= (mRTPageTable
->PageCount
- ReqPages
); ) {
150 // Check consecutive ReqPages pages.
152 for (SubIndex
= 0; SubIndex
< ReqPages
; SubIndex
++) {
153 if ((mRTPageTable
->Pages
[SubIndex
+ Index
].PageFlag
& RT_PAGE_USED
) != 0) {
158 if (SubIndex
== ReqPages
) {
160 // Succeed! Return the Starting Offset.
162 return RT_PAGES_TO_SIZE (Index
);
166 // Failed! Skip current free memory pages and adjacent Used pages
168 while ((mRTPageTable
->Pages
[SubIndex
+ Index
].PageFlag
& RT_PAGE_USED
) != 0) {
176 // Look up the free memory region from the beginning of the memory table
177 // until the StartCursorOffset
179 for (Index
= 0; Index
< (StartPageIndex
- ReqPages
); ) {
181 // Check Consecutive ReqPages Pages.
183 for (SubIndex
= 0; SubIndex
< ReqPages
; SubIndex
++) {
184 if ((mRTPageTable
->Pages
[SubIndex
+ Index
].PageFlag
& RT_PAGE_USED
) != 0) {
189 if (SubIndex
== ReqPages
) {
191 // Succeed! Return the Starting Offset.
193 return RT_PAGES_TO_SIZE (Index
);
197 // Failed! Skip current adjacent Used pages
199 while ((SubIndex
< (StartPageIndex
- ReqPages
)) &&
200 ((mRTPageTable
->Pages
[SubIndex
+ Index
].PageFlag
& RT_PAGE_USED
) != 0)) {
208 // No available region for object allocation!
215 Allocates a buffer at runtime phase.
217 @param[in] AllocationSize Bytes to be allocated.
219 @return A pointer to the allocated buffer or NULL if allocation fails.
224 IN UINTN AllocationSize
237 // Look for available consecutive memory region starting from LastEmptyPageOffset.
238 // If no proper memory region found, look up from the beginning.
239 // If still not found, return NULL to indicate failed allocation.
241 AllocOffset
= LookupFreeMemRegion (AllocationSize
);
242 if (AllocOffset
== (UINTN
)(-1)) {
247 // Allocates consecutive memory pages with length of Size. Update the page
248 // table status. Returns the starting address.
250 ReqPages
= RT_SIZE_TO_PAGES (AllocationSize
);
251 AllocPtr
= mRTPageTable
->DataAreaBase
+ AllocOffset
;
252 StartPage
= RT_SIZE_TO_PAGES (AllocOffset
);
254 while (Index
< ReqPages
) {
255 mRTPageTable
->Pages
[StartPage
+ Index
].PageFlag
|= RT_PAGE_USED
;
256 mRTPageTable
->Pages
[StartPage
+ Index
].StartPageOffset
= AllocOffset
;
261 mRTPageTable
->LastEmptyPageOffset
= AllocOffset
+ RT_PAGES_TO_SIZE (ReqPages
);
263 ZeroMem (AllocPtr
, AllocationSize
);
266 // Returns a void pointer to the allocated space
273 Frees a buffer that was previously allocated at runtime phase.
275 @param[in] Buffer Pointer to the buffer to free.
284 UINTN StartPageIndex
;
286 StartOffset
= (UINTN
)Buffer
- (UINTN
)mRTPageTable
->DataAreaBase
;
287 StartPageIndex
= RT_SIZE_TO_PAGES (mRTPageTable
->Pages
[RT_SIZE_TO_PAGES(StartOffset
)].StartPageOffset
);
289 while (StartPageIndex
< mRTPageTable
->PageCount
) {
290 if (((mRTPageTable
->Pages
[StartPageIndex
].PageFlag
& RT_PAGE_USED
) != 0) &&
291 (mRTPageTable
->Pages
[StartPageIndex
].StartPageOffset
== StartOffset
)) {
295 mRTPageTable
->Pages
[StartPageIndex
].PageFlag
&= ~RT_PAGE_USED
;
296 mRTPageTable
->Pages
[StartPageIndex
].PageFlag
|= RT_PAGE_FREE
;
297 mRTPageTable
->Pages
[StartPageIndex
].StartPageOffset
= 0;
310 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
312 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
313 event. It converts a pointer to a new virtual address.
315 @param[in] Event The event whose notification function is being invoked.
316 @param[in] Context The pointer to the notification function's context.
321 RuntimeCryptLibAddressChangeEvent (
327 // Converts a pointer for runtime memory management to a new virtual address.
329 EfiConvertPointer (0x0, (VOID
**) &mRTPageTable
->DataAreaBase
);
330 EfiConvertPointer (0x0, (VOID
**) &mRTPageTable
);
335 Constructor routine for runtime crypt library instance.
337 The constructor function pre-allocates space for runtime cryptographic operation.
339 @param ImageHandle The firmware allocated handle for the EFI image.
340 @param SystemTable A pointer to the EFI System Table.
342 @retval EFI_SUCCESS The construction succeeded.
343 @retval EFI_OUT_OF_RESOURCE Failed to allocate memory.
348 RuntimeCryptLibConstructor (
349 IN EFI_HANDLE ImageHandle
,
350 IN EFI_SYSTEM_TABLE
*SystemTable
357 // Pre-allocates runtime space for possible cryptographic operations
359 Buffer
= AllocateRuntimePool (MIN_REQUIRED_BLOCKS
* 1024);
360 Status
= InitializeScratchMemory (Buffer
, MIN_REQUIRED_BLOCKS
* 1024);
361 if (EFI_ERROR (Status
)) {
366 // Create address change event
368 Status
= gBS
->CreateEventEx (
371 RuntimeCryptLibAddressChangeEvent
,
373 &gEfiEventVirtualAddressChangeGuid
,
374 &mVirtualAddressChangeEvent
376 ASSERT_EFI_ERROR (Status
);
383 // -- Memory-Allocation Routines Wrapper for UEFI-OpenSSL Library --
386 /* Allocates memory blocks */
387 void *malloc (size_t size
)
389 return RuntimeAllocateMem ((UINTN
) size
);
392 /* Reallocate memory blocks */
393 void *realloc (void *ptr
, size_t size
)
397 UINTN StartPageIndex
;
401 return malloc (size
);
405 // Get Original Size of ptr
407 StartOffset
= (UINTN
)ptr
- (UINTN
)mRTPageTable
->DataAreaBase
;
408 StartPageIndex
= RT_SIZE_TO_PAGES (mRTPageTable
->Pages
[RT_SIZE_TO_PAGES (StartOffset
)].StartPageOffset
);
410 while (StartPageIndex
< mRTPageTable
->PageCount
) {
411 if (((mRTPageTable
->Pages
[StartPageIndex
].PageFlag
& RT_PAGE_USED
) != 0) &&
412 (mRTPageTable
->Pages
[StartPageIndex
].StartPageOffset
== StartOffset
)) {
420 if (size
<= RT_PAGES_TO_SIZE (PageCount
)) {
422 // Return the original pointer, if Caller try to reduce region size;
427 NewPtr
= RuntimeAllocateMem ((UINTN
) size
);
428 if (NewPtr
== NULL
) {
432 CopyMem (NewPtr
, ptr
, RT_PAGES_TO_SIZE (PageCount
));
434 RuntimeFreeMem (ptr
);
439 /* Deallocates or frees a memory block */
440 void free (void *ptr
)
443 // In Standard C, free() handles a null pointer argument transparently. This
444 // is not true of RuntimeFreeMem() below, so protect it.
447 RuntimeFreeMem (ptr
);