TianoCore EDK2 master
Loading...
Searching...
No Matches
RuntimeMemAllocation.c
Go to the documentation of this file.
1
10#include <CrtLibSupport.h>
14#include <Guid/EventGroup.h>
15
16// ----------------------------------------------------------------
17// Initial version. Needs further optimizations.
18// ----------------------------------------------------------------
19
20//
21// Definitions for Runtime Memory Operations
22//
23#define RT_PAGE_SIZE 0x200
24#define RT_PAGE_MASK 0x1FF
25#define RT_PAGE_SHIFT 9
26
27#define RT_SIZE_TO_PAGES(a) (((a) >> RT_PAGE_SHIFT) + (((a) & RT_PAGE_MASK) ? 1 : 0))
28#define RT_PAGES_TO_SIZE(a) ((a) << RT_PAGE_SHIFT)
29
30//
31// Page Flag Definitions
32//
33#define RT_PAGE_FREE 0x00000000
34#define RT_PAGE_USED 0x00000001
35
36#define MIN_REQUIRED_BLOCKS 1100
37
38//
39// Memory Page Table
40//
41typedef struct {
42 UINTN StartPageOffset; // Offset of the starting page allocated.
43 // Only available for USED pages.
44 UINT32 PageFlag; // Page Attributes.
46
47typedef struct {
48 UINTN PageCount;
49 UINTN LastEmptyPageOffset;
50 UINT8 *DataAreaBase; // Pointer to data Area.
51 RT_MEMORY_PAGE_ENTRY Pages[1]; // Page Table Entries.
53
54//
55// Global Page Table for Runtime Cryptographic Provider.
56//
57RT_MEMORY_PAGE_TABLE *mRTPageTable = NULL;
58
59//
60// Event for Runtime Address Conversion.
61//
62STATIC EFI_EVENT mVirtualAddressChangeEvent;
63
76 IN OUT UINT8 *ScratchBuffer,
77 IN UINTN ScratchBufferSize
78 )
79{
80 UINTN Index;
81 UINTN MemorySize;
82
83 //
84 // Parameters Checking
85 //
86 if (ScratchBuffer == NULL) {
87 return EFI_INVALID_PARAMETER;
88 }
89
90 if (ScratchBufferSize < MIN_REQUIRED_BLOCKS * 1024) {
91 return EFI_BUFFER_TOO_SMALL;
92 }
93
94 mRTPageTable = (RT_MEMORY_PAGE_TABLE *)ScratchBuffer;
95
96 //
97 // Initialize Internal Page Table for Memory Management
98 //
99 SetMem (mRTPageTable, ScratchBufferSize, 0xFF);
100 MemorySize = ScratchBufferSize - sizeof (RT_MEMORY_PAGE_TABLE) + sizeof (RT_MEMORY_PAGE_ENTRY);
101
102 mRTPageTable->PageCount = MemorySize / (RT_PAGE_SIZE + sizeof (RT_MEMORY_PAGE_ENTRY));
103 mRTPageTable->LastEmptyPageOffset = 0x0;
104
105 for (Index = 0; Index < mRTPageTable->PageCount; Index++) {
106 mRTPageTable->Pages[Index].PageFlag = RT_PAGE_FREE;
107 mRTPageTable->Pages[Index].StartPageOffset = 0;
108 }
109
110 mRTPageTable->DataAreaBase = ScratchBuffer + sizeof (RT_MEMORY_PAGE_TABLE) +
111 (mRTPageTable->PageCount - 1) * sizeof (RT_MEMORY_PAGE_ENTRY);
112
113 return EFI_SUCCESS;
114}
115
124UINTN
126 IN UINTN AllocationSize
127 )
128{
129 UINTN StartPageIndex;
130 UINTN Index;
131 UINTN SubIndex;
132 UINTN ReqPages;
133
134 StartPageIndex = RT_SIZE_TO_PAGES (mRTPageTable->LastEmptyPageOffset);
135 ReqPages = RT_SIZE_TO_PAGES (AllocationSize);
136 if (ReqPages > mRTPageTable->PageCount) {
137 //
138 // No enough region for object allocation.
139 //
140 return (UINTN)(-1);
141 }
142
143 //
144 // Look up the free memory region with in current memory map table.
145 //
146 for (Index = StartPageIndex; Index <= (mRTPageTable->PageCount - ReqPages); ) {
147 //
148 // Check consecutive ReqPages pages.
149 //
150 for (SubIndex = 0; SubIndex < ReqPages; SubIndex++) {
151 if ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0) {
152 break;
153 }
154 }
155
156 if (SubIndex == ReqPages) {
157 //
158 // Succeed! Return the Starting Offset.
159 //
160 return RT_PAGES_TO_SIZE (Index);
161 }
162
163 //
164 // Failed! Skip current free memory pages and adjacent Used pages
165 //
166 while ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0) {
167 SubIndex++;
168 }
169
170 Index += SubIndex;
171 }
172
173 //
174 // Look up the free memory region from the beginning of the memory table
175 // until the StartCursorOffset
176 //
177 if (ReqPages > StartPageIndex) {
178 //
179 // No enough region for object allocation.
180 //
181 return (UINTN)(-1);
182 }
183
184 for (Index = 0; Index < (StartPageIndex - ReqPages); ) {
185 //
186 // Check Consecutive ReqPages Pages.
187 //
188 for (SubIndex = 0; SubIndex < ReqPages; SubIndex++) {
189 if ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0) {
190 break;
191 }
192 }
193
194 if (SubIndex == ReqPages) {
195 //
196 // Succeed! Return the Starting Offset.
197 //
198 return RT_PAGES_TO_SIZE (Index);
199 }
200
201 //
202 // Failed! Skip current adjacent Used pages
203 //
204 while ((SubIndex < (StartPageIndex - ReqPages)) &&
205 ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0))
206 {
207 SubIndex++;
208 }
209
210 Index += SubIndex;
211 }
212
213 //
214 // No available region for object allocation!
215 //
216 return (UINTN)(-1);
217}
218
227VOID *
229 IN UINTN AllocationSize
230 )
231{
232 UINT8 *AllocPtr;
233 UINTN ReqPages;
234 UINTN Index;
235 UINTN StartPage;
236 UINTN AllocOffset;
237
238 AllocPtr = NULL;
239 ReqPages = 0;
240
241 //
242 // Look for available consecutive memory region starting from LastEmptyPageOffset.
243 // If no proper memory region found, look up from the beginning.
244 // If still not found, return NULL to indicate failed allocation.
245 //
246 AllocOffset = LookupFreeMemRegion (AllocationSize);
247 if (AllocOffset == (UINTN)(-1)) {
248 return NULL;
249 }
250
251 //
252 // Allocates consecutive memory pages with length of Size. Update the page
253 // table status. Returns the starting address.
254 //
255 ReqPages = RT_SIZE_TO_PAGES (AllocationSize);
256 AllocPtr = mRTPageTable->DataAreaBase + AllocOffset;
257 StartPage = RT_SIZE_TO_PAGES (AllocOffset);
258 Index = 0;
259 while (Index < ReqPages) {
260 mRTPageTable->Pages[StartPage + Index].PageFlag |= RT_PAGE_USED;
261 mRTPageTable->Pages[StartPage + Index].StartPageOffset = AllocOffset;
262
263 Index++;
264 }
265
266 mRTPageTable->LastEmptyPageOffset = AllocOffset + RT_PAGES_TO_SIZE (ReqPages);
267
268 ZeroMem (AllocPtr, AllocationSize);
269
270 //
271 // Returns a void pointer to the allocated space
272 //
273 return AllocPtr;
274}
275
282VOID
284 IN VOID *Buffer
285 )
286{
287 UINTN StartOffset;
288 UINTN StartPageIndex;
289
290 StartOffset = (UINTN)Buffer - (UINTN)mRTPageTable->DataAreaBase;
291 StartPageIndex = RT_SIZE_TO_PAGES (mRTPageTable->Pages[RT_SIZE_TO_PAGES (StartOffset)].StartPageOffset);
292
293 while (StartPageIndex < mRTPageTable->PageCount) {
294 if (((mRTPageTable->Pages[StartPageIndex].PageFlag & RT_PAGE_USED) != 0) &&
295 (mRTPageTable->Pages[StartPageIndex].StartPageOffset == StartOffset))
296 {
297 //
298 // Free this page
299 //
300 mRTPageTable->Pages[StartPageIndex].PageFlag &= ~RT_PAGE_USED;
301 mRTPageTable->Pages[StartPageIndex].PageFlag |= RT_PAGE_FREE;
302 mRTPageTable->Pages[StartPageIndex].StartPageOffset = 0;
303
304 StartPageIndex++;
305 } else {
306 break;
307 }
308 }
309
310 return;
311}
312
323VOID
324EFIAPI
326 IN EFI_EVENT Event,
327 IN VOID *Context
328 )
329{
330 //
331 // Converts a pointer for runtime memory management to a new virtual address.
332 //
333 EfiConvertPointer (0x0, (VOID **)&mRTPageTable->DataAreaBase);
334 EfiConvertPointer (0x0, (VOID **)&mRTPageTable);
335}
336
350EFIAPI
352 IN EFI_HANDLE ImageHandle,
353 IN EFI_SYSTEM_TABLE *SystemTable
354 )
355{
356 EFI_STATUS Status;
357 VOID *Buffer;
358
359 //
360 // Pre-allocates runtime space for possible cryptographic operations
361 //
362 Buffer = AllocateRuntimePool (MIN_REQUIRED_BLOCKS * 1024);
363 Status = InitializeScratchMemory (Buffer, MIN_REQUIRED_BLOCKS * 1024);
364 if (EFI_ERROR (Status)) {
365 return Status;
366 }
367
368 //
369 // Create address change event
370 //
371 Status = gBS->CreateEventEx (
372 EVT_NOTIFY_SIGNAL,
373 TPL_NOTIFY,
375 NULL,
376 &gEfiEventVirtualAddressChangeGuid,
377 &mVirtualAddressChangeEvent
378 );
379 ASSERT_EFI_ERROR (Status);
380
381 return Status;
382}
383
384//
385// -- Memory-Allocation Routines Wrapper for UEFI-OpenSSL Library --
386//
387
388/* Allocates memory blocks */
389void *
390malloc (
391 size_t size
392 )
393{
394 return RuntimeAllocateMem ((UINTN)size);
395}
396
397/* Reallocate memory blocks */
398void *
399realloc (
400 void *ptr,
401 size_t size
402 )
403{
404 VOID *NewPtr;
405 UINTN StartOffset;
406 UINTN StartPageIndex;
407 UINTN PageCount;
408
409 if (ptr == NULL) {
410 return malloc (size);
411 }
412
413 //
414 // Get Original Size of ptr
415 //
416 StartOffset = (UINTN)ptr - (UINTN)mRTPageTable->DataAreaBase;
417 StartPageIndex = RT_SIZE_TO_PAGES (mRTPageTable->Pages[RT_SIZE_TO_PAGES (StartOffset)].StartPageOffset);
418 PageCount = 0;
419 while (StartPageIndex < mRTPageTable->PageCount) {
420 if (((mRTPageTable->Pages[StartPageIndex].PageFlag & RT_PAGE_USED) != 0) &&
421 (mRTPageTable->Pages[StartPageIndex].StartPageOffset == StartOffset))
422 {
423 StartPageIndex++;
424 PageCount++;
425 } else {
426 break;
427 }
428 }
429
430 if (size <= RT_PAGES_TO_SIZE (PageCount)) {
431 //
432 // Return the original pointer, if Caller try to reduce region size;
433 //
434 return ptr;
435 }
436
437 NewPtr = RuntimeAllocateMem ((UINTN)size);
438 if (NewPtr == NULL) {
439 return NULL;
440 }
441
442 CopyMem (NewPtr, ptr, RT_PAGES_TO_SIZE (PageCount));
443
444 RuntimeFreeMem (ptr);
445
446 return NewPtr;
447}
448
449/* Deallocates or frees a memory block */
450void
451free (
452 void *ptr
453 )
454{
455 //
456 // In Standard C, free() handles a null pointer argument transparently. This
457 // is not true of RuntimeFreeMem() below, so protect it.
458 //
459 if (ptr != NULL) {
460 RuntimeFreeMem (ptr);
461 }
462}
UINT64 UINTN
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI SetMem(OUT VOID *Buffer, IN UINTN Length, IN UINT8 Value)
Definition: SetMemWrapper.c:38
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID *EFIAPI AllocateRuntimePool(IN UINTN AllocationSize)
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
VOID EFIAPI RuntimeCryptLibAddressChangeEvent(IN EFI_EVENT Event, IN VOID *Context)
UINTN LookupFreeMemRegion(IN UINTN AllocationSize)
VOID * RuntimeAllocateMem(IN UINTN AllocationSize)
EFI_STATUS EFIAPI RuntimeCryptLibConstructor(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
EFI_STATUS InitializeScratchMemory(IN OUT UINT8 *ScratchBuffer, IN UINTN ScratchBufferSize)
VOID RuntimeFreeMem(IN VOID *Buffer)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_STATUS EFIAPI EfiConvertPointer(IN UINTN DebugDisposition, IN OUT VOID **Address)
Definition: RuntimeLib.c:561