]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Mem/Pool.c
Code scrub for DxeCore
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Pool.c
1 /** @file
2 UEFI Memory pool management functions.
3
4 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <DxeMain.h>
16
17 #define POOL_FREE_SIGNATURE EFI_SIGNATURE_32('p','f','r','0')
18 typedef struct {
19 UINT32 Signature;
20 UINT32 Index;
21 LIST_ENTRY Link;
22 } POOL_FREE;
23
24
25 #define POOL_HEAD_SIGNATURE EFI_SIGNATURE_32('p','h','d','0')
26 typedef struct {
27 UINT32 Signature;
28 UINT32 Size;
29 EFI_MEMORY_TYPE Type;
30 UINTN Reserved;
31 CHAR8 Data[1];
32 } POOL_HEAD;
33
34 #define SIZE_OF_POOL_HEAD EFI_FIELD_OFFSET(POOL_HEAD,Data)
35
36 #define POOL_TAIL_SIGNATURE EFI_SIGNATURE_32('p','t','a','l')
37 typedef struct {
38 UINT32 Signature;
39 UINT32 Size;
40 } POOL_TAIL;
41
42
43 #define POOL_SHIFT 7
44
45 #define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))
46
47 #define HEAD_TO_TAIL(a) \
48 ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
49
50
51 #define SIZE_TO_LIST(a) ((a) >> POOL_SHIFT)
52 #define LIST_TO_SIZE(a) ((a+1) << POOL_SHIFT)
53
54 #define MAX_POOL_LIST SIZE_TO_LIST(DEFAULT_PAGE_ALLOCATION)
55
56 #define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)
57
58 //
59 // Globals
60 //
61
62 #define POOL_SIGNATURE EFI_SIGNATURE_32('p','l','s','t')
63 typedef struct {
64 INTN Signature;
65 UINTN Used;
66 EFI_MEMORY_TYPE MemoryType;
67 LIST_ENTRY FreeList[MAX_POOL_LIST];
68 LIST_ENTRY Link;
69 } POOL;
70
71 //
72 // Pool header for each memory type.
73 //
74 POOL mPoolHead[EfiMaxMemoryType];
75
76 //
77 // List of pool header to search for the appropriate memory type.
78 //
79 LIST_ENTRY mPoolHeadList;
80
81
82 /**
83 Called to initialize the pool.
84
85 **/
86 VOID
87 CoreInitializePool (
88 VOID
89 )
90 {
91 UINTN Type;
92 UINTN Index;
93
94 for (Type=0; Type < EfiMaxMemoryType; Type++) {
95 mPoolHead[Type].Signature = 0;
96 mPoolHead[Type].Used = 0;
97 mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;
98 for (Index=0; Index < MAX_POOL_LIST; Index++) {
99 InitializeListHead (&mPoolHead[Type].FreeList[Index]);
100 }
101 }
102 InitializeListHead (&mPoolHeadList);
103 }
104
105
106 /**
107 Look up pool head for specified memory type.
108
109 @param MemoryType Memory type of which pool head is looked for
110
111 @return Pointer of Corresponding pool head.
112
113 **/
114 POOL *
115 LookupPoolHead (
116 IN EFI_MEMORY_TYPE MemoryType
117 )
118 {
119 LIST_ENTRY *Link;
120 POOL *Pool;
121 UINTN Index;
122
123 if (MemoryType >= 0 && MemoryType < EfiMaxMemoryType) {
124 return &mPoolHead[MemoryType];
125 }
126
127 if (MemoryType < 0) {
128
129 for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {
130 Pool = CR(Link, POOL, Link, POOL_SIGNATURE);
131 if (Pool->MemoryType == MemoryType) {
132 return Pool;
133 }
134 }
135
136 Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));
137 if (Pool == NULL) {
138 return NULL;
139 }
140
141 Pool->Signature = POOL_SIGNATURE;
142 Pool->Used = 0;
143 Pool->MemoryType = MemoryType;
144 for (Index=0; Index < MAX_POOL_LIST; Index++) {
145 InitializeListHead (&Pool->FreeList[Index]);
146 }
147
148 InsertHeadList (&mPoolHeadList, &Pool->Link);
149
150 return Pool;
151 }
152
153 return NULL;
154 }
155
156
157
158 /**
159 Allocate pool of a particular type.
160
161 @param PoolType Type of pool to allocate
162 @param Size The amount of pool to allocate
163 @param Buffer The address to return a pointer to the allocated
164 pool
165
166 @retval EFI_INVALID_PARAMETER PoolType not valid
167 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
168 @retval EFI_SUCCESS Pool successfully allocated.
169
170 **/
171 EFI_STATUS
172 EFIAPI
173 CoreAllocatePool (
174 IN EFI_MEMORY_TYPE PoolType,
175 IN UINTN Size,
176 OUT VOID **Buffer
177 )
178 {
179 EFI_STATUS Status;
180
181 //
182 // If it's not a valid type, fail it
183 //
184 if ((PoolType >= EfiMaxMemoryType && PoolType <= 0x7fffffff) ||
185 PoolType == EfiConventionalMemory) {
186 return EFI_INVALID_PARAMETER;
187 }
188
189 *Buffer = NULL;
190
191 //
192 // If size is too large, fail it
193 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES
194 //
195 if (Size > MAX_POOL_SIZE) {
196 return EFI_OUT_OF_RESOURCES;
197 }
198
199 //
200 // Acquire the memory lock and make the allocation
201 //
202 Status = CoreAcquireLockOrFail (&gMemoryLock);
203 if (EFI_ERROR (Status)) {
204 return EFI_OUT_OF_RESOURCES;
205 }
206
207 *Buffer = CoreAllocatePoolI (PoolType, Size);
208 CoreReleaseMemoryLock ();
209 return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
210 }
211
212
213
214 /**
215 Internal function to allocate pool of a particular type.
216 Caller must have the memory lock held
217
218 @param PoolType Type of pool to allocate
219 @param Size The amount of pool to allocate
220
221 @return The allocate pool, or NULL
222
223 **/
224 VOID *
225 CoreAllocatePoolI (
226 IN EFI_MEMORY_TYPE PoolType,
227 IN UINTN Size
228 )
229 {
230 POOL *Pool;
231 POOL_FREE *Free;
232 POOL_HEAD *Head;
233 POOL_TAIL *Tail;
234 CHAR8 *NewPage;
235 VOID *Buffer;
236 UINTN Index;
237 UINTN FSize;
238 UINTN Offset;
239 UINTN Adjustment;
240 UINTN NoPages;
241
242 ASSERT_LOCKED (&gMemoryLock);
243
244 //
245 // Adjust the size by the pool header & tail overhead
246 //
247
248 //
249 // Adjusting the Size to be of proper alignment so that
250 // we don't get an unaligned access fault later when
251 // pool_Tail is being initialized
252 //
253 ALIGN_VARIABLE (Size, Adjustment);
254
255 Size += POOL_OVERHEAD;
256 Index = SIZE_TO_LIST(Size);
257 Pool = LookupPoolHead (PoolType);
258 if (Pool== NULL) {
259 return NULL;
260 }
261 Head = NULL;
262
263 //
264 // If allocation is over max size, just allocate pages for the request
265 // (slow)
266 //
267 if (Index >= MAX_POOL_LIST) {
268 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;
269 NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);
270 Head = CoreAllocatePoolPages (PoolType, NoPages, DEFAULT_PAGE_ALLOCATION);
271 goto Done;
272 }
273
274 //
275 // If there's no free pool in the proper list size, go get some more pages
276 //
277 if (IsListEmpty (&Pool->FreeList[Index])) {
278
279 //
280 // Get another page
281 //
282 NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);
283 if (NewPage == NULL) {
284 goto Done;
285 }
286
287 //
288 // Carve up new page into free pool blocks
289 //
290 Offset = 0;
291 while (Offset < DEFAULT_PAGE_ALLOCATION) {
292 ASSERT (Index < MAX_POOL_LIST);
293 FSize = LIST_TO_SIZE(Index);
294
295 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {
296 Free = (POOL_FREE *) &NewPage[Offset];
297 Free->Signature = POOL_FREE_SIGNATURE;
298 Free->Index = (UINT32)Index;
299 InsertHeadList (&Pool->FreeList[Index], &Free->Link);
300 Offset += FSize;
301 }
302
303 Index -= 1;
304 }
305
306 ASSERT (Offset == DEFAULT_PAGE_ALLOCATION);
307 Index = SIZE_TO_LIST(Size);
308 }
309
310 //
311 // Remove entry from free pool list
312 //
313 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
314 RemoveEntryList (&Free->Link);
315
316 Head = (POOL_HEAD *) Free;
317
318 Done:
319 Buffer = NULL;
320
321 if (Head != NULL) {
322
323 //
324 // If we have a pool buffer, fill in the header & tail info
325 //
326 Head->Signature = POOL_HEAD_SIGNATURE;
327 Head->Size = (UINT32) Size;
328 Head->Type = (EFI_MEMORY_TYPE) PoolType;
329 Tail = HEAD_TO_TAIL (Head);
330 Tail->Signature = POOL_TAIL_SIGNATURE;
331 Tail->Size = (UINT32) Size;
332 Buffer = Head->Data;
333 DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);
334
335 DEBUG ((
336 DEBUG_POOL,
337 "AllocatePoolI: Type %x, Addr %x (len %x) %,d\n", PoolType,
338 Buffer,
339 Size - POOL_OVERHEAD,
340 Pool->Used
341 ));
342
343 //
344 // Account the allocation
345 //
346 Pool->Used += Size;
347
348 } else {
349 DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %d bytes\n", Size));
350 }
351
352 return Buffer;
353 }
354
355
356
357 /**
358 Frees pool.
359
360 @param Buffer The allocated pool entry to free
361
362 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
363 @retval EFI_SUCCESS Pool successfully freed.
364
365 **/
366 EFI_STATUS
367 EFIAPI
368 CoreFreePool (
369 IN VOID *Buffer
370 )
371 {
372 EFI_STATUS Status;
373
374 if (Buffer == NULL) {
375 return EFI_INVALID_PARAMETER;
376 }
377
378 CoreAcquireMemoryLock ();
379 Status = CoreFreePoolI (Buffer);
380 CoreReleaseMemoryLock ();
381 return Status;
382 }
383
384
385
386 /**
387 Internal function to free a pool entry.
388 Caller must have the memory lock held
389
390 @param Buffer The allocated pool entry to free
391
392 @retval EFI_INVALID_PARAMETER Buffer not valid
393 @retval EFI_SUCCESS Buffer successfully freed.
394
395 **/
396 EFI_STATUS
397 CoreFreePoolI (
398 IN VOID *Buffer
399 )
400 {
401 POOL *Pool;
402 POOL_HEAD *Head;
403 POOL_TAIL *Tail;
404 POOL_FREE *Free;
405 UINTN Index;
406 UINTN NoPages;
407 UINTN Size;
408 CHAR8 *NewPage;
409 UINTN FSize;
410 UINTN Offset;
411 BOOLEAN AllFree;
412
413 ASSERT(NULL != Buffer);
414 //
415 // Get the head & tail of the pool entry
416 //
417 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);
418 ASSERT(NULL != Head);
419
420 if (Head->Signature != POOL_HEAD_SIGNATURE) {
421 return EFI_INVALID_PARAMETER;
422 }
423
424 Tail = HEAD_TO_TAIL (Head);
425 ASSERT(NULL != Tail);
426
427 //
428 // Debug
429 //
430 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);
431 ASSERT (Head->Size == Tail->Size);
432 ASSERT_LOCKED (&gMemoryLock);
433
434 if (Tail->Signature != POOL_TAIL_SIGNATURE) {
435 return EFI_INVALID_PARAMETER;
436 }
437
438 if (Head->Size != Tail->Size) {
439 return EFI_INVALID_PARAMETER;
440 }
441
442 //
443 // Determine the pool type and account for it
444 //
445 Size = Head->Size;
446 Pool = LookupPoolHead (Head->Type);
447 if (Pool == NULL) {
448 return EFI_INVALID_PARAMETER;
449 }
450 Pool->Used -= Size;
451 DEBUG ((DEBUG_POOL, "FreePool: %x (len %x) %,d\n", Head->Data, Head->Size - POOL_OVERHEAD, Pool->Used));
452
453 //
454 // Determine the pool list
455 //
456 Index = SIZE_TO_LIST(Size);
457 DEBUG_CLEAR_MEMORY (Head, Size);
458
459 //
460 // If it's not on the list, it must be pool pages
461 //
462 if (Index >= MAX_POOL_LIST) {
463
464 //
465 // Return the memory pages back to free memory
466 //
467 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;
468 NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);
469 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);
470
471 } else {
472
473 //
474 // Put the pool entry onto the free pool list
475 //
476 Free = (POOL_FREE *) Head;
477 ASSERT(NULL != Free);
478 Free->Signature = POOL_FREE_SIGNATURE;
479 Free->Index = (UINT32)Index;
480 InsertHeadList (&Pool->FreeList[Index], &Free->Link);
481
482 //
483 // See if all the pool entries in the same page as Free are freed pool
484 // entries
485 //
486 NewPage = (CHAR8 *)((UINTN)Free & ~((DEFAULT_PAGE_ALLOCATION) -1));
487 Free = (POOL_FREE *) &NewPage[0];
488 ASSERT(Free != NULL);
489
490 if (Free->Signature == POOL_FREE_SIGNATURE) {
491
492 Index = Free->Index;
493
494 AllFree = TRUE;
495 Offset = 0;
496
497 while ((Offset < DEFAULT_PAGE_ALLOCATION) && (AllFree)) {
498 FSize = LIST_TO_SIZE(Index);
499 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {
500 Free = (POOL_FREE *) &NewPage[Offset];
501 ASSERT(NULL != Free);
502 if (Free->Signature != POOL_FREE_SIGNATURE) {
503 AllFree = FALSE;
504 }
505 Offset += FSize;
506 }
507 Index -= 1;
508 }
509
510 if (AllFree) {
511
512 //
513 // All of the pool entries in the same page as Free are free pool
514 // entries
515 // Remove all of these pool entries from the free loop lists.
516 //
517 Free = (POOL_FREE *) &NewPage[0];
518 ASSERT(NULL != Free);
519 Index = Free->Index;
520 Offset = 0;
521
522 while (Offset < DEFAULT_PAGE_ALLOCATION) {
523 FSize = LIST_TO_SIZE(Index);
524 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {
525 Free = (POOL_FREE *) &NewPage[Offset];
526 ASSERT(NULL != Free);
527 RemoveEntryList (&Free->Link);
528 Offset += FSize;
529 }
530 Index -= 1;
531 }
532
533 //
534 // Free the page
535 //
536 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION));
537 }
538 }
539 }
540
541 //
542 // If this is an OS specific memory type, then check to see if the last
543 // portion of that memory type has been freed. If it has, then free the
544 // list entry for that memory type
545 //
546 if (Pool->MemoryType < 0 && Pool->Used == 0) {
547 RemoveEntryList (&Pool->Link);
548 CoreFreePoolI (Pool);
549 }
550
551 return EFI_SUCCESS;
552 }