]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/Dxe/Mem/Pool.c
MdeModulePkg DxeCore: Enhance memory profile for memory leak detection
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Pool.c
... / ...
CommitLineData
1/** @file\r
2 UEFI Memory pool management functions.\r
3\r
4Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "DxeMain.h"\r
16#include "Imem.h"\r
17\r
18#define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0')\r
19typedef struct {\r
20 UINT32 Signature;\r
21 UINT32 Index;\r
22 LIST_ENTRY Link;\r
23} POOL_FREE;\r
24\r
25\r
26#define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')\r
27typedef struct {\r
28 UINT32 Signature;\r
29 UINT32 Reserved;\r
30 EFI_MEMORY_TYPE Type;\r
31 UINTN Size;\r
32 CHAR8 Data[1];\r
33} POOL_HEAD;\r
34\r
35#define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)\r
36\r
37#define POOL_TAIL_SIGNATURE SIGNATURE_32('p','t','a','l')\r
38typedef struct {\r
39 UINT32 Signature;\r
40 UINT32 Reserved;\r
41 UINTN Size;\r
42} POOL_TAIL;\r
43\r
44#define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))\r
45\r
46#define HEAD_TO_TAIL(a) \\r
47 ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));\r
48\r
49//\r
50// Each element is the sum of the 2 previous ones: this allows us to migrate\r
51// blocks between bins by splitting them up, while not wasting too much memory\r
52// as we would in a strict power-of-2 sequence\r
53//\r
54STATIC CONST UINT16 mPoolSizeTable[] = {\r
55 128, 256, 384, 640, 1024, 1664, 2688, 4352, 7040, 11392, 18432, 29824\r
56};\r
57\r
58#define SIZE_TO_LIST(a) (GetPoolIndexFromSize (a))\r
59#define LIST_TO_SIZE(a) (mPoolSizeTable [a])\r
60\r
61#define MAX_POOL_LIST (sizeof (mPoolSizeTable) / sizeof (mPoolSizeTable[0]))\r
62\r
63#define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)\r
64\r
65//\r
66// Globals\r
67//\r
68\r
69#define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')\r
70typedef struct {\r
71 INTN Signature;\r
72 UINTN Used;\r
73 EFI_MEMORY_TYPE MemoryType;\r
74 LIST_ENTRY FreeList[MAX_POOL_LIST];\r
75 LIST_ENTRY Link;\r
76} POOL;\r
77\r
78//\r
79// Pool header for each memory type.\r
80//\r
81POOL mPoolHead[EfiMaxMemoryType];\r
82\r
83//\r
84// List of pool header to search for the appropriate memory type.\r
85//\r
86LIST_ENTRY mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);\r
87\r
88/**\r
89 Get pool size table index from the specified size.\r
90\r
91 @param Size The specified size to get index from pool table.\r
92\r
93 @return The index of pool size table.\r
94\r
95**/\r
96STATIC\r
97UINTN\r
98GetPoolIndexFromSize (\r
99 UINTN Size\r
100 )\r
101{\r
102 UINTN Index;\r
103\r
104 for (Index = 0; Index < MAX_POOL_LIST; Index++) {\r
105 if (mPoolSizeTable [Index] >= Size) {\r
106 return Index;\r
107 }\r
108 }\r
109 return MAX_POOL_LIST;\r
110}\r
111\r
112/**\r
113 Called to initialize the pool.\r
114\r
115**/\r
116VOID\r
117CoreInitializePool (\r
118 VOID\r
119 )\r
120{\r
121 UINTN Type;\r
122 UINTN Index;\r
123\r
124 for (Type=0; Type < EfiMaxMemoryType; Type++) {\r
125 mPoolHead[Type].Signature = 0;\r
126 mPoolHead[Type].Used = 0;\r
127 mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;\r
128 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
129 InitializeListHead (&mPoolHead[Type].FreeList[Index]);\r
130 }\r
131 }\r
132}\r
133\r
134\r
135/**\r
136 Look up pool head for specified memory type.\r
137\r
138 @param MemoryType Memory type of which pool head is looked for\r
139\r
140 @return Pointer of Corresponding pool head.\r
141\r
142**/\r
143POOL *\r
144LookupPoolHead (\r
145 IN EFI_MEMORY_TYPE MemoryType\r
146 )\r
147{\r
148 LIST_ENTRY *Link;\r
149 POOL *Pool;\r
150 UINTN Index;\r
151\r
152 if ((UINT32)MemoryType < EfiMaxMemoryType) {\r
153 return &mPoolHead[MemoryType];\r
154 }\r
155\r
156 //\r
157 // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI\r
158 // OS loaders that are provided by operating system vendors.\r
159 // MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.\r
160 //\r
161 if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {\r
162\r
163 for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {\r
164 Pool = CR(Link, POOL, Link, POOL_SIGNATURE);\r
165 if (Pool->MemoryType == MemoryType) {\r
166 return Pool;\r
167 }\r
168 }\r
169\r
170 Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));\r
171 if (Pool == NULL) {\r
172 return NULL;\r
173 }\r
174\r
175 Pool->Signature = POOL_SIGNATURE;\r
176 Pool->Used = 0;\r
177 Pool->MemoryType = MemoryType;\r
178 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
179 InitializeListHead (&Pool->FreeList[Index]);\r
180 }\r
181\r
182 InsertHeadList (&mPoolHeadList, &Pool->Link);\r
183\r
184 return Pool;\r
185 }\r
186\r
187 return NULL;\r
188}\r
189\r
190\r
191\r
192/**\r
193 Allocate pool of a particular type.\r
194\r
195 @param PoolType Type of pool to allocate\r
196 @param Size The amount of pool to allocate\r
197 @param Buffer The address to return a pointer to the allocated\r
198 pool\r
199\r
200 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
201 PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.\r
202 PoolType is EfiPersistentMemory.\r
203 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
204 @retval EFI_SUCCESS Pool successfully allocated.\r
205\r
206**/\r
207EFI_STATUS\r
208EFIAPI\r
209CoreInternalAllocatePool (\r
210 IN EFI_MEMORY_TYPE PoolType,\r
211 IN UINTN Size,\r
212 OUT VOID **Buffer\r
213 )\r
214{\r
215 EFI_STATUS Status;\r
216\r
217 //\r
218 // If it's not a valid type, fail it\r
219 //\r
220 if ((PoolType >= EfiMaxMemoryType && PoolType < MEMORY_TYPE_OEM_RESERVED_MIN) ||\r
221 (PoolType == EfiConventionalMemory) || (PoolType == EfiPersistentMemory)) {\r
222 return EFI_INVALID_PARAMETER;\r
223 }\r
224\r
225 if (Buffer == NULL) {\r
226 return EFI_INVALID_PARAMETER;\r
227 }\r
228\r
229 *Buffer = NULL;\r
230\r
231 //\r
232 // If size is too large, fail it\r
233 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES\r
234 //\r
235 if (Size > MAX_POOL_SIZE) {\r
236 return EFI_OUT_OF_RESOURCES;\r
237 }\r
238\r
239 //\r
240 // Acquire the memory lock and make the allocation\r
241 //\r
242 Status = CoreAcquireLockOrFail (&gMemoryLock);\r
243 if (EFI_ERROR (Status)) {\r
244 return EFI_OUT_OF_RESOURCES;\r
245 }\r
246\r
247 *Buffer = CoreAllocatePoolI (PoolType, Size);\r
248 CoreReleaseMemoryLock ();\r
249 return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;\r
250}\r
251\r
252/**\r
253 Allocate pool of a particular type.\r
254\r
255 @param PoolType Type of pool to allocate\r
256 @param Size The amount of pool to allocate\r
257 @param Buffer The address to return a pointer to the allocated\r
258 pool\r
259\r
260 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
261 PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.\r
262 PoolType is EfiPersistentMemory.\r
263 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
264 @retval EFI_SUCCESS Pool successfully allocated.\r
265\r
266**/\r
267EFI_STATUS\r
268EFIAPI\r
269CoreAllocatePool (\r
270 IN EFI_MEMORY_TYPE PoolType,\r
271 IN UINTN Size,\r
272 OUT VOID **Buffer\r
273 )\r
274{\r
275 EFI_STATUS Status;\r
276\r
277 Status = CoreInternalAllocatePool (PoolType, Size, Buffer);\r
278 if (!EFI_ERROR (Status)) {\r
279 CoreUpdateProfile (\r
280 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
281 MemoryProfileActionAllocatePool,\r
282 PoolType,\r
283 Size,\r
284 *Buffer,\r
285 NULL\r
286 );\r
287 InstallMemoryAttributesTableOnMemoryAllocation (PoolType);\r
288 }\r
289 return Status;\r
290}\r
291\r
292/**\r
293 Internal function to allocate pool of a particular type.\r
294 Caller must have the memory lock held\r
295\r
296 @param PoolType Type of pool to allocate\r
297 @param Size The amount of pool to allocate\r
298\r
299 @return The allocate pool, or NULL\r
300\r
301**/\r
302VOID *\r
303CoreAllocatePoolI (\r
304 IN EFI_MEMORY_TYPE PoolType,\r
305 IN UINTN Size\r
306 )\r
307{\r
308 POOL *Pool;\r
309 POOL_FREE *Free;\r
310 POOL_HEAD *Head;\r
311 POOL_TAIL *Tail;\r
312 CHAR8 *NewPage;\r
313 VOID *Buffer;\r
314 UINTN Index;\r
315 UINTN FSize;\r
316 UINTN Offset, MaxOffset;\r
317 UINTN NoPages;\r
318 UINTN Granularity;\r
319\r
320 ASSERT_LOCKED (&gMemoryLock);\r
321\r
322 if (PoolType == EfiACPIReclaimMemory ||\r
323 PoolType == EfiACPIMemoryNVS ||\r
324 PoolType == EfiRuntimeServicesCode ||\r
325 PoolType == EfiRuntimeServicesData) {\r
326\r
327 Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
328 } else {\r
329 Granularity = DEFAULT_PAGE_ALLOCATION;\r
330 }\r
331\r
332 //\r
333 // Adjust the size by the pool header & tail overhead\r
334 //\r
335\r
336 //\r
337 // Adjusting the Size to be of proper alignment so that\r
338 // we don't get an unaligned access fault later when\r
339 // pool_Tail is being initialized\r
340 //\r
341 Size = ALIGN_VARIABLE (Size);\r
342\r
343 Size += POOL_OVERHEAD;\r
344 Index = SIZE_TO_LIST(Size);\r
345 Pool = LookupPoolHead (PoolType);\r
346 if (Pool== NULL) {\r
347 return NULL;\r
348 }\r
349 Head = NULL;\r
350\r
351 //\r
352 // If allocation is over max size, just allocate pages for the request\r
353 // (slow)\r
354 //\r
355 if (Index >= SIZE_TO_LIST (Granularity)) {\r
356 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
357 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
358 Head = CoreAllocatePoolPages (PoolType, NoPages, Granularity);\r
359 goto Done;\r
360 }\r
361\r
362 //\r
363 // If there's no free pool in the proper list size, go get some more pages\r
364 //\r
365 if (IsListEmpty (&Pool->FreeList[Index])) {\r
366\r
367 Offset = LIST_TO_SIZE (Index);\r
368 MaxOffset = Granularity;\r
369\r
370 //\r
371 // Check the bins holding larger blocks, and carve one up if needed\r
372 //\r
373 while (++Index < SIZE_TO_LIST (Granularity)) {\r
374 if (!IsListEmpty (&Pool->FreeList[Index])) {\r
375 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
376 RemoveEntryList (&Free->Link);\r
377 NewPage = (VOID *) Free;\r
378 MaxOffset = LIST_TO_SIZE (Index);\r
379 goto Carve;\r
380 }\r
381 }\r
382\r
383 //\r
384 // Get another page\r
385 //\r
386 NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (Granularity), Granularity);\r
387 if (NewPage == NULL) {\r
388 goto Done;\r
389 }\r
390\r
391 //\r
392 // Serve the allocation request from the head of the allocated block\r
393 //\r
394Carve:\r
395 Head = (POOL_HEAD *) NewPage;\r
396\r
397 //\r
398 // Carve up remaining space into free pool blocks\r
399 //\r
400 Index--;\r
401 while (Offset < MaxOffset) {\r
402 ASSERT (Index < MAX_POOL_LIST);\r
403 FSize = LIST_TO_SIZE(Index);\r
404\r
405 while (Offset + FSize <= MaxOffset) {\r
406 Free = (POOL_FREE *) &NewPage[Offset];\r
407 Free->Signature = POOL_FREE_SIGNATURE;\r
408 Free->Index = (UINT32)Index;\r
409 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
410 Offset += FSize;\r
411 }\r
412 Index -= 1;\r
413 }\r
414\r
415 ASSERT (Offset == MaxOffset);\r
416 goto Done;\r
417 }\r
418\r
419 //\r
420 // Remove entry from free pool list\r
421 //\r
422 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
423 RemoveEntryList (&Free->Link);\r
424\r
425 Head = (POOL_HEAD *) Free;\r
426\r
427Done:\r
428 Buffer = NULL;\r
429\r
430 if (Head != NULL) {\r
431\r
432 //\r
433 // If we have a pool buffer, fill in the header & tail info\r
434 //\r
435 Head->Signature = POOL_HEAD_SIGNATURE;\r
436 Head->Size = Size;\r
437 Head->Type = (EFI_MEMORY_TYPE) PoolType;\r
438 Tail = HEAD_TO_TAIL (Head);\r
439 Tail->Signature = POOL_TAIL_SIGNATURE;\r
440 Tail->Size = Size;\r
441 Buffer = Head->Data;\r
442 DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);\r
443\r
444 DEBUG ((\r
445 DEBUG_POOL,\r
446 "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,\r
447 Buffer,\r
448 (UINT64)(Size - POOL_OVERHEAD),\r
449 (UINT64) Pool->Used\r
450 ));\r
451\r
452 //\r
453 // Account the allocation\r
454 //\r
455 Pool->Used += Size;\r
456\r
457 } else {\r
458 DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));\r
459 }\r
460\r
461 return Buffer;\r
462}\r
463\r
464\r
465\r
466/**\r
467 Frees pool.\r
468\r
469 @param Buffer The allocated pool entry to free\r
470 @param PoolType Pointer to pool type\r
471\r
472 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
473 @retval EFI_SUCCESS Pool successfully freed.\r
474\r
475**/\r
476EFI_STATUS\r
477EFIAPI\r
478CoreInternalFreePool (\r
479 IN VOID *Buffer,\r
480 OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r
481 )\r
482{\r
483 EFI_STATUS Status;\r
484\r
485 if (Buffer == NULL) {\r
486 return EFI_INVALID_PARAMETER;\r
487 }\r
488\r
489 CoreAcquireMemoryLock ();\r
490 Status = CoreFreePoolI (Buffer, PoolType);\r
491 CoreReleaseMemoryLock ();\r
492 return Status;\r
493}\r
494\r
495/**\r
496 Frees pool.\r
497\r
498 @param Buffer The allocated pool entry to free\r
499\r
500 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
501 @retval EFI_SUCCESS Pool successfully freed.\r
502\r
503**/\r
504EFI_STATUS\r
505EFIAPI\r
506CoreFreePool (\r
507 IN VOID *Buffer\r
508 )\r
509{\r
510 EFI_STATUS Status;\r
511 EFI_MEMORY_TYPE PoolType;\r
512\r
513 Status = CoreInternalFreePool (Buffer, &PoolType);\r
514 if (!EFI_ERROR (Status)) {\r
515 CoreUpdateProfile (\r
516 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
517 MemoryProfileActionFreePool,\r
518 PoolType,\r
519 0,\r
520 Buffer,\r
521 NULL\r
522 );\r
523 InstallMemoryAttributesTableOnMemoryAllocation (PoolType);\r
524 }\r
525 return Status;\r
526}\r
527\r
528/**\r
529 Internal function to free a pool entry.\r
530 Caller must have the memory lock held\r
531\r
532 @param Buffer The allocated pool entry to free\r
533 @param PoolType Pointer to pool type\r
534\r
535 @retval EFI_INVALID_PARAMETER Buffer not valid\r
536 @retval EFI_SUCCESS Buffer successfully freed.\r
537\r
538**/\r
539EFI_STATUS\r
540CoreFreePoolI (\r
541 IN VOID *Buffer,\r
542 OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r
543 )\r
544{\r
545 POOL *Pool;\r
546 POOL_HEAD *Head;\r
547 POOL_TAIL *Tail;\r
548 POOL_FREE *Free;\r
549 UINTN Index;\r
550 UINTN NoPages;\r
551 UINTN Size;\r
552 CHAR8 *NewPage;\r
553 UINTN Offset;\r
554 BOOLEAN AllFree;\r
555 UINTN Granularity;\r
556\r
557 ASSERT(Buffer != NULL);\r
558 //\r
559 // Get the head & tail of the pool entry\r
560 //\r
561 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
562 ASSERT(Head != NULL);\r
563\r
564 if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
565 return EFI_INVALID_PARAMETER;\r
566 }\r
567\r
568 Tail = HEAD_TO_TAIL (Head);\r
569 ASSERT(Tail != NULL);\r
570\r
571 //\r
572 // Debug\r
573 //\r
574 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
575 ASSERT (Head->Size == Tail->Size);\r
576 ASSERT_LOCKED (&gMemoryLock);\r
577\r
578 if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
579 return EFI_INVALID_PARAMETER;\r
580 }\r
581\r
582 if (Head->Size != Tail->Size) {\r
583 return EFI_INVALID_PARAMETER;\r
584 }\r
585\r
586 //\r
587 // Determine the pool type and account for it\r
588 //\r
589 Size = Head->Size;\r
590 Pool = LookupPoolHead (Head->Type);\r
591 if (Pool == NULL) {\r
592 return EFI_INVALID_PARAMETER;\r
593 }\r
594 Pool->Used -= Size;\r
595 DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
596\r
597 if (Head->Type == EfiACPIReclaimMemory ||\r
598 Head->Type == EfiACPIMemoryNVS ||\r
599 Head->Type == EfiRuntimeServicesCode ||\r
600 Head->Type == EfiRuntimeServicesData) {\r
601\r
602 Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
603 } else {\r
604 Granularity = DEFAULT_PAGE_ALLOCATION;\r
605 }\r
606\r
607 if (PoolType != NULL) {\r
608 *PoolType = Head->Type;\r
609 }\r
610\r
611 //\r
612 // Determine the pool list\r
613 //\r
614 Index = SIZE_TO_LIST(Size);\r
615 DEBUG_CLEAR_MEMORY (Head, Size);\r
616\r
617 //\r
618 // If it's not on the list, it must be pool pages\r
619 //\r
620 if (Index >= SIZE_TO_LIST (Granularity)) {\r
621\r
622 //\r
623 // Return the memory pages back to free memory\r
624 //\r
625 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
626 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
627 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
628\r
629 } else {\r
630\r
631 //\r
632 // Put the pool entry onto the free pool list\r
633 //\r
634 Free = (POOL_FREE *) Head;\r
635 ASSERT(Free != NULL);\r
636 Free->Signature = POOL_FREE_SIGNATURE;\r
637 Free->Index = (UINT32)Index;\r
638 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
639\r
640 //\r
641 // See if all the pool entries in the same page as Free are freed pool\r
642 // entries\r
643 //\r
644 NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));\r
645 Free = (POOL_FREE *) &NewPage[0];\r
646 ASSERT(Free != NULL);\r
647\r
648 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
649\r
650 AllFree = TRUE;\r
651 Offset = 0;\r
652\r
653 while ((Offset < Granularity) && (AllFree)) {\r
654 Free = (POOL_FREE *) &NewPage[Offset];\r
655 ASSERT(Free != NULL);\r
656 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
657 AllFree = FALSE;\r
658 }\r
659 Offset += LIST_TO_SIZE(Free->Index);\r
660 }\r
661\r
662 if (AllFree) {\r
663\r
664 //\r
665 // All of the pool entries in the same page as Free are free pool\r
666 // entries\r
667 // Remove all of these pool entries from the free loop lists.\r
668 //\r
669 Free = (POOL_FREE *) &NewPage[0];\r
670 ASSERT(Free != NULL);\r
671 Offset = 0;\r
672\r
673 while (Offset < Granularity) {\r
674 Free = (POOL_FREE *) &NewPage[Offset];\r
675 ASSERT(Free != NULL);\r
676 RemoveEntryList (&Free->Link);\r
677 Offset += LIST_TO_SIZE(Free->Index);\r
678 }\r
679\r
680 //\r
681 // Free the page\r
682 //\r
683 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (Granularity));\r
684 }\r
685 }\r
686 }\r
687\r
688 //\r
689 // If this is an OS/OEM specific memory type, then check to see if the last\r
690 // portion of that memory type has been freed. If it has, then free the\r
691 // list entry for that memory type\r
692 //\r
693 if (((UINT32) Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && Pool->Used == 0) {\r
694 RemoveEntryList (&Pool->Link);\r
695 CoreFreePoolI (Pool, NULL);\r
696 }\r
697\r
698 return EFI_SUCCESS;\r
699}\r
700\r