2 Light-weight Memory Management Routines for OpenSSL-based Crypto
3 Library at Runtime Phase.
5 Copyright (c) 2009 - 2016, 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 <OpenSslSupport.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/UefiRuntimeLib.h>
19 #include <Guid/EventGroup.h>
21 //----------------------------------------------------------------
22 // Initial version. Needs further optimizations.
23 //----------------------------------------------------------------
26 // Definitions for Runtime Memory Operations
28 #define RT_PAGE_SIZE 0x200
29 #define RT_PAGE_MASK 0x1FF
30 #define RT_PAGE_SHIFT 9
32 #define RT_SIZE_TO_PAGES(a) (((a) >> RT_PAGE_SHIFT) + (((a) & RT_PAGE_MASK) ? 1 : 0))
33 #define RT_PAGES_TO_SIZE(a) ((a) << RT_PAGE_SHIFT)
36 // Page Flag Definitions
38 #define RT_PAGE_FREE 0x00000000
39 #define RT_PAGE_USED 0x00000001
41 #define MIN_REQUIRED_BLOCKS 600
47 UINTN StartPageOffset
; // Offset of the starting page allocated.
48 // Only available for USED pages.
49 UINT32 PageFlag
; // Page Attributes.
50 } RT_MEMORY_PAGE_ENTRY
;
54 UINTN LastEmptyPageOffset
;
55 UINT8
*DataAreaBase
; // Pointer to data Area.
56 RT_MEMORY_PAGE_ENTRY Pages
[1]; // Page Table Entries.
57 } RT_MEMORY_PAGE_TABLE
;
60 // Global Page Table for Runtime Cryptographic Provider.
62 RT_MEMORY_PAGE_TABLE
*mRTPageTable
= NULL
;
65 // Event for Runtime Address Conversion.
67 STATIC EFI_EVENT mVirtualAddressChangeEvent
;
71 Initializes pre-allocated memory pointed by ScratchBuffer for subsequent
74 @param[in, out] ScratchBuffer Pointer to user-supplied memory buffer.
75 @param[in] ScratchBufferSize Size of supplied buffer in bytes.
77 @retval EFI_SUCCESS Successful initialization.
81 InitializeScratchMemory (
82 IN OUT UINT8
*ScratchBuffer
,
83 IN UINTN ScratchBufferSize
90 // Parameters Checking
92 if (ScratchBuffer
== NULL
) {
93 return EFI_INVALID_PARAMETER
;
96 if (ScratchBufferSize
< MIN_REQUIRED_BLOCKS
* 1024) {
97 return EFI_BUFFER_TOO_SMALL
;
100 mRTPageTable
= (RT_MEMORY_PAGE_TABLE
*)ScratchBuffer
;
103 // Initialize Internal Page Table for Memory Management
105 SetMem (mRTPageTable
, ScratchBufferSize
, 0xFF);
106 MemorySize
= ScratchBufferSize
- sizeof (RT_MEMORY_PAGE_TABLE
) + sizeof (RT_MEMORY_PAGE_ENTRY
);
108 mRTPageTable
->PageCount
= MemorySize
/ (RT_PAGE_SIZE
+ sizeof (RT_MEMORY_PAGE_ENTRY
));
109 mRTPageTable
->LastEmptyPageOffset
= 0x0;
111 for (Index
= 0; Index
< mRTPageTable
->PageCount
; Index
++) {
112 mRTPageTable
->Pages
[Index
].PageFlag
= RT_PAGE_FREE
;
113 mRTPageTable
->Pages
[Index
].StartPageOffset
= 0;
116 mRTPageTable
->DataAreaBase
= ScratchBuffer
+ sizeof (RT_MEMORY_PAGE_TABLE
) +
117 (mRTPageTable
->PageCount
- 1) * sizeof (RT_MEMORY_PAGE_ENTRY
);
124 Look-up Free memory Region for object allocation.
126 @param[in] AllocationSize Bytes to be allocated.
128 @return Return available page offset for object allocation.
132 LookupFreeMemRegion (
133 IN UINTN AllocationSize
136 UINTN StartPageIndex
;
141 StartPageIndex
= RT_SIZE_TO_PAGES (mRTPageTable
->LastEmptyPageOffset
);
142 ReqPages
= RT_SIZE_TO_PAGES (AllocationSize
);
145 // Look up the free memory region with in current memory map table.
147 for (Index
= StartPageIndex
; Index
<= (mRTPageTable
->PageCount
- ReqPages
); ) {
149 // Check consecutive ReqPages pages.
151 for (SubIndex
= 0; SubIndex
< ReqPages
; SubIndex
++) {
152 if ((mRTPageTable
->Pages
[SubIndex
+ Index
].PageFlag
& RT_PAGE_USED
) != 0) {
157 if (SubIndex
== ReqPages
) {
159 // Succeed! Return the Starting Offset.
161 return RT_PAGES_TO_SIZE (Index
);
165 // Failed! Skip current free memory pages and adjacent Used pages
167 while ((mRTPageTable
->Pages
[SubIndex
+ Index
].PageFlag
& RT_PAGE_USED
) != 0) {
175 // Look up the free memory region from the beginning of the memory table
176 // until the StartCursorOffset
178 for (Index
= 0; Index
< (StartPageIndex
- ReqPages
); ) {
180 // Check Consecutive ReqPages Pages.
182 for (SubIndex
= 0; SubIndex
< ReqPages
; SubIndex
++) {
183 if ((mRTPageTable
->Pages
[SubIndex
+ Index
].PageFlag
& RT_PAGE_USED
) != 0) {
188 if (SubIndex
== ReqPages
) {
190 // Succeed! Return the Starting Offset.
192 return RT_PAGES_TO_SIZE (Index
);
196 // Failed! Skip current adjacent Used pages
198 while ((SubIndex
< (StartPageIndex
- ReqPages
)) &&
199 ((mRTPageTable
->Pages
[SubIndex
+ Index
].PageFlag
& RT_PAGE_USED
) != 0)) {
207 // No available region for object allocation!
214 Allocates a buffer at runtime phase.
216 @param[in] AllocationSize Bytes to be allocated.
218 @return A pointer to the allocated buffer or NULL if allocation fails.
223 IN UINTN AllocationSize
236 // Look for available consecutive memory region starting from LastEmptyPageOffset.
237 // If no proper memory region found, look up from the beginning.
238 // If still not found, return NULL to indicate failed allocation.
240 AllocOffset
= LookupFreeMemRegion (AllocationSize
);
241 if (AllocOffset
== (UINTN
)(-1)) {
246 // Allocates consecutive memory pages with length of Size. Update the page
247 // table status. Returns the starting address.
249 ReqPages
= RT_SIZE_TO_PAGES (AllocationSize
);
250 AllocPtr
= mRTPageTable
->DataAreaBase
+ AllocOffset
;
251 StartPage
= RT_SIZE_TO_PAGES (AllocOffset
);
253 while (Index
< ReqPages
) {
254 mRTPageTable
->Pages
[StartPage
+ Index
].PageFlag
|= RT_PAGE_USED
;
255 mRTPageTable
->Pages
[StartPage
+ Index
].StartPageOffset
= AllocOffset
;
260 mRTPageTable
->LastEmptyPageOffset
= AllocOffset
+ RT_PAGES_TO_SIZE (ReqPages
);
262 ZeroMem (AllocPtr
, AllocationSize
);
265 // Returns a void pointer to the allocated space
272 Frees a buffer that was previously allocated at runtime phase.
274 @param[in] Buffer Pointer to the buffer to free.
283 UINTN StartPageIndex
;
285 StartOffset
= (UINTN
) ((UINT8
*)Buffer
- mRTPageTable
->DataAreaBase
);
286 StartPageIndex
= RT_SIZE_TO_PAGES (mRTPageTable
->Pages
[RT_SIZE_TO_PAGES(StartOffset
)].StartPageOffset
);
288 while (StartPageIndex
< mRTPageTable
->PageCount
) {
289 if (((mRTPageTable
->Pages
[StartPageIndex
].PageFlag
& RT_PAGE_USED
) != 0) &&
290 (mRTPageTable
->Pages
[StartPageIndex
].StartPageOffset
== StartOffset
)) {
294 mRTPageTable
->Pages
[StartPageIndex
].PageFlag
&= ~RT_PAGE_USED
;
295 mRTPageTable
->Pages
[StartPageIndex
].PageFlag
|= RT_PAGE_FREE
;
296 mRTPageTable
->Pages
[StartPageIndex
].StartPageOffset
= 0;
309 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
311 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
312 event. It converts a pointer to a new virtual address.
314 @param[in] Event The event whose notification function is being invoked.
315 @param[in] Context The pointer to the notification function's context.
320 RuntimeCryptLibAddressChangeEvent (
326 // Converts a pointer for runtime memory management to a new virtual address.
328 EfiConvertPointer (0x0, (VOID
**) &mRTPageTable
->DataAreaBase
);
329 EfiConvertPointer (0x0, (VOID
**) &mRTPageTable
);
334 Constructor routine for runtime crypt library instance.
336 The constructor function pre-allocates space for runtime cryptographic operation.
338 @param ImageHandle The firmware allocated handle for the EFI image.
339 @param SystemTable A pointer to the EFI System Table.
341 @retval EFI_SUCCESS The construction succeeded.
342 @retval EFI_OUT_OF_RESOURCE Failed to allocate memory.
347 RuntimeCryptLibConstructor (
348 IN EFI_HANDLE ImageHandle
,
349 IN EFI_SYSTEM_TABLE
*SystemTable
356 // Pre-allocates runtime space for possible cryptographic operations
358 Buffer
= AllocateRuntimePool (MIN_REQUIRED_BLOCKS
* 1024);
359 Status
= InitializeScratchMemory (Buffer
, MIN_REQUIRED_BLOCKS
* 1024);
360 if (EFI_ERROR (Status
)) {
365 // Create address change event
367 Status
= gBS
->CreateEventEx (
370 RuntimeCryptLibAddressChangeEvent
,
372 &gEfiEventVirtualAddressChangeGuid
,
373 &mVirtualAddressChangeEvent
375 ASSERT_EFI_ERROR (Status
);
382 // -- Memory-Allocation Routines Wrapper for UEFI-OpenSSL Library --
385 /* Allocates memory blocks */
386 void *malloc (size_t size
)
388 return RuntimeAllocateMem ((UINTN
) size
);
391 /* Reallocate memory blocks */
392 void *realloc (void *ptr
, size_t size
)
396 UINTN StartPageIndex
;
400 return malloc (size
);
404 // Get Original Size of ptr
406 StartOffset
= (UINTN
) ((UINT8
*)ptr
- mRTPageTable
->DataAreaBase
);
407 StartPageIndex
= RT_SIZE_TO_PAGES (mRTPageTable
->Pages
[RT_SIZE_TO_PAGES (StartOffset
)].StartPageOffset
);
409 while (StartPageIndex
< mRTPageTable
->PageCount
) {
410 if (((mRTPageTable
->Pages
[StartPageIndex
].PageFlag
& RT_PAGE_USED
) != 0) &&
411 (mRTPageTable
->Pages
[StartPageIndex
].StartPageOffset
== StartOffset
)) {
419 if (size
<= RT_PAGES_TO_SIZE (PageCount
)) {
421 // Return the original pointer, if Caller try to reduce region size;
426 NewPtr
= RuntimeAllocateMem ((UINTN
) size
);
427 if (NewPtr
== NULL
) {
431 CopyMem (NewPtr
, ptr
, RT_PAGES_TO_SIZE (PageCount
));
433 RuntimeFreeMem (ptr
);
438 /* Deallocates or frees a memory block */
439 void free (void *ptr
)
442 // In Standard C, free() handles a null pointer argument transparently. This
443 // is not true of RuntimeFreeMem() below, so protect it.
446 RuntimeFreeMem (ptr
);