]> git.proxmox.com Git - mirror_edk2.git/blob - CryptoPkg/Library/BaseCryptLib/SysCall/RuntimeMemAllocation.c
CryptoPkg/CrtLibSupport: add secure_getenv() stub function
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / SysCall / RuntimeMemAllocation.c
1 /** @file
2 Light-weight Memory Management Routines for OpenSSL-based Crypto
3 Library at Runtime Phase.
4
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
10
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.
13
14 **/
15
16 #include <CrtLibSupport.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/UefiRuntimeLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Guid/EventGroup.h>
21
22 //----------------------------------------------------------------
23 // Initial version. Needs further optimizations.
24 //----------------------------------------------------------------
25
26 //
27 // Definitions for Runtime Memory Operations
28 //
29 #define RT_PAGE_SIZE 0x200
30 #define RT_PAGE_MASK 0x1FF
31 #define RT_PAGE_SHIFT 9
32
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)
35
36 //
37 // Page Flag Definitions
38 //
39 #define RT_PAGE_FREE 0x00000000
40 #define RT_PAGE_USED 0x00000001
41
42 #define MIN_REQUIRED_BLOCKS 600
43
44 //
45 // Memory Page Table
46 //
47 typedef struct {
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;
52
53 typedef struct {
54 UINTN PageCount;
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;
59
60 //
61 // Global Page Table for Runtime Cryptographic Provider.
62 //
63 RT_MEMORY_PAGE_TABLE *mRTPageTable = NULL;
64
65 //
66 // Event for Runtime Address Conversion.
67 //
68 STATIC EFI_EVENT mVirtualAddressChangeEvent;
69
70
71 /**
72 Initializes pre-allocated memory pointed by ScratchBuffer for subsequent
73 runtime use.
74
75 @param[in, out] ScratchBuffer Pointer to user-supplied memory buffer.
76 @param[in] ScratchBufferSize Size of supplied buffer in bytes.
77
78 @retval EFI_SUCCESS Successful initialization.
79
80 **/
81 EFI_STATUS
82 InitializeScratchMemory (
83 IN OUT UINT8 *ScratchBuffer,
84 IN UINTN ScratchBufferSize
85 )
86 {
87 UINTN Index;
88 UINTN MemorySize;
89
90 //
91 // Parameters Checking
92 //
93 if (ScratchBuffer == NULL) {
94 return EFI_INVALID_PARAMETER;
95 }
96
97 if (ScratchBufferSize < MIN_REQUIRED_BLOCKS * 1024) {
98 return EFI_BUFFER_TOO_SMALL;
99 }
100
101 mRTPageTable = (RT_MEMORY_PAGE_TABLE *)ScratchBuffer;
102
103 //
104 // Initialize Internal Page Table for Memory Management
105 //
106 SetMem (mRTPageTable, ScratchBufferSize, 0xFF);
107 MemorySize = ScratchBufferSize - sizeof (RT_MEMORY_PAGE_TABLE) + sizeof (RT_MEMORY_PAGE_ENTRY);
108
109 mRTPageTable->PageCount = MemorySize / (RT_PAGE_SIZE + sizeof (RT_MEMORY_PAGE_ENTRY));
110 mRTPageTable->LastEmptyPageOffset = 0x0;
111
112 for (Index = 0; Index < mRTPageTable->PageCount; Index++) {
113 mRTPageTable->Pages[Index].PageFlag = RT_PAGE_FREE;
114 mRTPageTable->Pages[Index].StartPageOffset = 0;
115 }
116
117 mRTPageTable->DataAreaBase = ScratchBuffer + sizeof (RT_MEMORY_PAGE_TABLE) +
118 (mRTPageTable->PageCount - 1) * sizeof (RT_MEMORY_PAGE_ENTRY);
119
120 return EFI_SUCCESS;
121 }
122
123
124 /**
125 Look-up Free memory Region for object allocation.
126
127 @param[in] AllocationSize Bytes to be allocated.
128
129 @return Return available page offset for object allocation.
130
131 **/
132 UINTN
133 LookupFreeMemRegion (
134 IN UINTN AllocationSize
135 )
136 {
137 UINTN StartPageIndex;
138 UINTN Index;
139 UINTN SubIndex;
140 UINTN ReqPages;
141
142 StartPageIndex = RT_SIZE_TO_PAGES (mRTPageTable->LastEmptyPageOffset);
143 ReqPages = RT_SIZE_TO_PAGES (AllocationSize);
144
145 //
146 // Look up the free memory region with in current memory map table.
147 //
148 for (Index = StartPageIndex; Index <= (mRTPageTable->PageCount - ReqPages); ) {
149 //
150 // Check consecutive ReqPages pages.
151 //
152 for (SubIndex = 0; SubIndex < ReqPages; SubIndex++) {
153 if ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0) {
154 break;
155 }
156 }
157
158 if (SubIndex == ReqPages) {
159 //
160 // Succeed! Return the Starting Offset.
161 //
162 return RT_PAGES_TO_SIZE (Index);
163 }
164
165 //
166 // Failed! Skip current free memory pages and adjacent Used pages
167 //
168 while ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0) {
169 SubIndex++;
170 }
171
172 Index += SubIndex;
173 }
174
175 //
176 // Look up the free memory region from the beginning of the memory table
177 // until the StartCursorOffset
178 //
179 for (Index = 0; Index < (StartPageIndex - ReqPages); ) {
180 //
181 // Check Consecutive ReqPages Pages.
182 //
183 for (SubIndex = 0; SubIndex < ReqPages; SubIndex++) {
184 if ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0) {
185 break;
186 }
187 }
188
189 if (SubIndex == ReqPages) {
190 //
191 // Succeed! Return the Starting Offset.
192 //
193 return RT_PAGES_TO_SIZE (Index);
194 }
195
196 //
197 // Failed! Skip current adjacent Used pages
198 //
199 while ((SubIndex < (StartPageIndex - ReqPages)) &&
200 ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0)) {
201 SubIndex++;
202 }
203
204 Index += SubIndex;
205 }
206
207 //
208 // No available region for object allocation!
209 //
210 return (UINTN)(-1);
211 }
212
213
214 /**
215 Allocates a buffer at runtime phase.
216
217 @param[in] AllocationSize Bytes to be allocated.
218
219 @return A pointer to the allocated buffer or NULL if allocation fails.
220
221 **/
222 VOID *
223 RuntimeAllocateMem (
224 IN UINTN AllocationSize
225 )
226 {
227 UINT8 *AllocPtr;
228 UINTN ReqPages;
229 UINTN Index;
230 UINTN StartPage;
231 UINTN AllocOffset;
232
233 AllocPtr = NULL;
234 ReqPages = 0;
235
236 //
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.
240 //
241 AllocOffset = LookupFreeMemRegion (AllocationSize);
242 if (AllocOffset == (UINTN)(-1)) {
243 return NULL;
244 }
245
246 //
247 // Allocates consecutive memory pages with length of Size. Update the page
248 // table status. Returns the starting address.
249 //
250 ReqPages = RT_SIZE_TO_PAGES (AllocationSize);
251 AllocPtr = mRTPageTable->DataAreaBase + AllocOffset;
252 StartPage = RT_SIZE_TO_PAGES (AllocOffset);
253 Index = 0;
254 while (Index < ReqPages) {
255 mRTPageTable->Pages[StartPage + Index].PageFlag |= RT_PAGE_USED;
256 mRTPageTable->Pages[StartPage + Index].StartPageOffset = AllocOffset;
257
258 Index++;
259 }
260
261 mRTPageTable->LastEmptyPageOffset = AllocOffset + RT_PAGES_TO_SIZE (ReqPages);
262
263 ZeroMem (AllocPtr, AllocationSize);
264
265 //
266 // Returns a void pointer to the allocated space
267 //
268 return AllocPtr;
269 }
270
271
272 /**
273 Frees a buffer that was previously allocated at runtime phase.
274
275 @param[in] Buffer Pointer to the buffer to free.
276
277 **/
278 VOID
279 RuntimeFreeMem (
280 IN VOID *Buffer
281 )
282 {
283 UINTN StartOffset;
284 UINTN StartPageIndex;
285
286 StartOffset = (UINTN)Buffer - (UINTN)mRTPageTable->DataAreaBase;
287 StartPageIndex = RT_SIZE_TO_PAGES (mRTPageTable->Pages[RT_SIZE_TO_PAGES(StartOffset)].StartPageOffset);
288
289 while (StartPageIndex < mRTPageTable->PageCount) {
290 if (((mRTPageTable->Pages[StartPageIndex].PageFlag & RT_PAGE_USED) != 0) &&
291 (mRTPageTable->Pages[StartPageIndex].StartPageOffset == StartOffset)) {
292 //
293 // Free this page
294 //
295 mRTPageTable->Pages[StartPageIndex].PageFlag &= ~RT_PAGE_USED;
296 mRTPageTable->Pages[StartPageIndex].PageFlag |= RT_PAGE_FREE;
297 mRTPageTable->Pages[StartPageIndex].StartPageOffset = 0;
298
299 StartPageIndex++;
300 } else {
301 break;
302 }
303 }
304
305 return;
306 }
307
308
309 /**
310 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
311
312 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
313 event. It converts a pointer to a new virtual address.
314
315 @param[in] Event The event whose notification function is being invoked.
316 @param[in] Context The pointer to the notification function's context.
317
318 **/
319 VOID
320 EFIAPI
321 RuntimeCryptLibAddressChangeEvent (
322 IN EFI_EVENT Event,
323 IN VOID *Context
324 )
325 {
326 //
327 // Converts a pointer for runtime memory management to a new virtual address.
328 //
329 EfiConvertPointer (0x0, (VOID **) &mRTPageTable->DataAreaBase);
330 EfiConvertPointer (0x0, (VOID **) &mRTPageTable);
331 }
332
333
334 /**
335 Constructor routine for runtime crypt library instance.
336
337 The constructor function pre-allocates space for runtime cryptographic operation.
338
339 @param ImageHandle The firmware allocated handle for the EFI image.
340 @param SystemTable A pointer to the EFI System Table.
341
342 @retval EFI_SUCCESS The construction succeeded.
343 @retval EFI_OUT_OF_RESOURCE Failed to allocate memory.
344
345 **/
346 EFI_STATUS
347 EFIAPI
348 RuntimeCryptLibConstructor (
349 IN EFI_HANDLE ImageHandle,
350 IN EFI_SYSTEM_TABLE *SystemTable
351 )
352 {
353 EFI_STATUS Status;
354 VOID *Buffer;
355
356 //
357 // Pre-allocates runtime space for possible cryptographic operations
358 //
359 Buffer = AllocateRuntimePool (MIN_REQUIRED_BLOCKS * 1024);
360 Status = InitializeScratchMemory (Buffer, MIN_REQUIRED_BLOCKS * 1024);
361 if (EFI_ERROR (Status)) {
362 return Status;
363 }
364
365 //
366 // Create address change event
367 //
368 Status = gBS->CreateEventEx (
369 EVT_NOTIFY_SIGNAL,
370 TPL_NOTIFY,
371 RuntimeCryptLibAddressChangeEvent,
372 NULL,
373 &gEfiEventVirtualAddressChangeGuid,
374 &mVirtualAddressChangeEvent
375 );
376 ASSERT_EFI_ERROR (Status);
377
378 return Status;
379 }
380
381
382 //
383 // -- Memory-Allocation Routines Wrapper for UEFI-OpenSSL Library --
384 //
385
386 /* Allocates memory blocks */
387 void *malloc (size_t size)
388 {
389 return RuntimeAllocateMem ((UINTN) size);
390 }
391
392 /* Reallocate memory blocks */
393 void *realloc (void *ptr, size_t size)
394 {
395 VOID *NewPtr;
396 UINTN StartOffset;
397 UINTN StartPageIndex;
398 UINTN PageCount;
399
400 if (ptr == NULL) {
401 return malloc (size);
402 }
403
404 //
405 // Get Original Size of ptr
406 //
407 StartOffset = (UINTN)ptr - (UINTN)mRTPageTable->DataAreaBase;
408 StartPageIndex = RT_SIZE_TO_PAGES (mRTPageTable->Pages[RT_SIZE_TO_PAGES (StartOffset)].StartPageOffset);
409 PageCount = 0;
410 while (StartPageIndex < mRTPageTable->PageCount) {
411 if (((mRTPageTable->Pages[StartPageIndex].PageFlag & RT_PAGE_USED) != 0) &&
412 (mRTPageTable->Pages[StartPageIndex].StartPageOffset == StartOffset)) {
413 StartPageIndex++;
414 PageCount++;
415 } else {
416 break;
417 }
418 }
419
420 if (size <= RT_PAGES_TO_SIZE (PageCount)) {
421 //
422 // Return the original pointer, if Caller try to reduce region size;
423 //
424 return ptr;
425 }
426
427 NewPtr = RuntimeAllocateMem ((UINTN) size);
428 if (NewPtr == NULL) {
429 return NULL;
430 }
431
432 CopyMem (NewPtr, ptr, RT_PAGES_TO_SIZE (PageCount));
433
434 RuntimeFreeMem (ptr);
435
436 return NewPtr;
437 }
438
439 /* Deallocates or frees a memory block */
440 void free (void *ptr)
441 {
442 //
443 // In Standard C, free() handles a null pointer argument transparently. This
444 // is not true of RuntimeFreeMem() below, so protect it.
445 //
446 if (ptr != NULL) {
447 RuntimeFreeMem (ptr);
448 }
449 }