]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/Dxe/Mem/Pool.c
Add patch-able PCD to support binary modification of MRC module.
[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 - 2014, 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 64, 128, 192, 320, 512, 832, 1344, 2176, 3520, 5696, 9216, 14912, 24128\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
88STATIC\r
89UINTN\r
90GetPoolIndexFromSize (\r
91 UINTN Size\r
92 )\r
93{\r
94 UINTN Index;\r
95\r
96 for (Index = 0; Index < MAX_POOL_LIST; Index++) {\r
97 if (mPoolSizeTable [Index] >= Size) {\r
98 return Index;\r
99 }\r
100 }\r
101 return MAX_POOL_LIST;\r
102}\r
103\r
104/**\r
105 Called to initialize the pool.\r
106\r
107**/\r
108VOID\r
109CoreInitializePool (\r
110 VOID\r
111 )\r
112{\r
113 UINTN Type;\r
114 UINTN Index;\r
115\r
116 for (Type=0; Type < EfiMaxMemoryType; Type++) {\r
117 mPoolHead[Type].Signature = 0;\r
118 mPoolHead[Type].Used = 0;\r
119 mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;\r
120 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
121 InitializeListHead (&mPoolHead[Type].FreeList[Index]);\r
122 }\r
123 }\r
124}\r
125\r
126\r
127/**\r
128 Look up pool head for specified memory type.\r
129\r
130 @param MemoryType Memory type of which pool head is looked for\r
131\r
132 @return Pointer of Corresponding pool head.\r
133\r
134**/\r
135POOL *\r
136LookupPoolHead (\r
137 IN EFI_MEMORY_TYPE MemoryType\r
138 )\r
139{\r
140 LIST_ENTRY *Link;\r
141 POOL *Pool;\r
142 UINTN Index;\r
143\r
144 if ((UINT32)MemoryType < EfiMaxMemoryType) {\r
145 return &mPoolHead[MemoryType];\r
146 }\r
147\r
148 //\r
149 // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI \r
150 // OS loaders that are provided by operating system vendors\r
151 //\r
152 if ((INT32)MemoryType < 0) {\r
153\r
154 for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {\r
155 Pool = CR(Link, POOL, Link, POOL_SIGNATURE);\r
156 if (Pool->MemoryType == MemoryType) {\r
157 return Pool;\r
158 }\r
159 }\r
160\r
161 Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));\r
162 if (Pool == NULL) {\r
163 return NULL;\r
164 }\r
165\r
166 Pool->Signature = POOL_SIGNATURE;\r
167 Pool->Used = 0;\r
168 Pool->MemoryType = MemoryType;\r
169 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
170 InitializeListHead (&Pool->FreeList[Index]);\r
171 }\r
172\r
173 InsertHeadList (&mPoolHeadList, &Pool->Link);\r
174\r
175 return Pool;\r
176 }\r
177\r
178 return NULL;\r
179}\r
180\r
181\r
182\r
183/**\r
184 Allocate pool of a particular type.\r
185\r
186 @param PoolType Type of pool to allocate\r
187 @param Size The amount of pool to allocate\r
188 @param Buffer The address to return a pointer to the allocated\r
189 pool\r
190\r
191 @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL. \r
192 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
193 @retval EFI_SUCCESS Pool successfully allocated.\r
194\r
195**/\r
196EFI_STATUS\r
197EFIAPI\r
198CoreInternalAllocatePool (\r
199 IN EFI_MEMORY_TYPE PoolType,\r
200 IN UINTN Size,\r
201 OUT VOID **Buffer\r
202 )\r
203{\r
204 EFI_STATUS Status;\r
205\r
206 //\r
207 // If it's not a valid type, fail it\r
208 //\r
209 if ((PoolType >= EfiMaxMemoryType && PoolType <= 0x7fffffff) ||\r
210 PoolType == EfiConventionalMemory) {\r
211 return EFI_INVALID_PARAMETER;\r
212 }\r
213\r
214 if (Buffer == NULL) {\r
215 return EFI_INVALID_PARAMETER;\r
216 }\r
217\r
218 *Buffer = NULL;\r
219\r
220 //\r
221 // If size is too large, fail it\r
222 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES\r
223 //\r
224 if (Size > MAX_POOL_SIZE) {\r
225 return EFI_OUT_OF_RESOURCES;\r
226 }\r
227\r
228 //\r
229 // Acquire the memory lock and make the allocation\r
230 //\r
231 Status = CoreAcquireLockOrFail (&gMemoryLock);\r
232 if (EFI_ERROR (Status)) {\r
233 return EFI_OUT_OF_RESOURCES;\r
234 }\r
235\r
236 *Buffer = CoreAllocatePoolI (PoolType, Size);\r
237 CoreReleaseMemoryLock ();\r
238 return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;\r
239}\r
240\r
241/**\r
242 Allocate pool of a particular type.\r
243\r
244 @param PoolType Type of pool to allocate\r
245 @param Size The amount of pool to allocate\r
246 @param Buffer The address to return a pointer to the allocated\r
247 pool\r
248\r
249 @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL. \r
250 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
251 @retval EFI_SUCCESS Pool successfully allocated.\r
252\r
253**/\r
254EFI_STATUS\r
255EFIAPI\r
256CoreAllocatePool (\r
257 IN EFI_MEMORY_TYPE PoolType,\r
258 IN UINTN Size,\r
259 OUT VOID **Buffer\r
260 )\r
261{\r
262 EFI_STATUS Status;\r
263\r
264 Status = CoreInternalAllocatePool (PoolType, Size, Buffer);\r
265 if (!EFI_ERROR (Status)) {\r
266 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePool, PoolType, Size, *Buffer);\r
267 }\r
268 return Status;\r
269}\r
270\r
271/**\r
272 Internal function to allocate pool of a particular type.\r
273 Caller must have the memory lock held\r
274\r
275 @param PoolType Type of pool to allocate\r
276 @param Size The amount of pool to allocate\r
277\r
278 @return The allocate pool, or NULL\r
279\r
280**/\r
281VOID *\r
282CoreAllocatePoolI (\r
283 IN EFI_MEMORY_TYPE PoolType,\r
284 IN UINTN Size\r
285 )\r
286{\r
287 POOL *Pool;\r
288 POOL_FREE *Free;\r
289 POOL_HEAD *Head;\r
290 POOL_TAIL *Tail;\r
291 CHAR8 *NewPage;\r
292 VOID *Buffer;\r
293 UINTN Index;\r
294 UINTN FSize;\r
295 UINTN Offset, MaxOffset;\r
296 UINTN NoPages;\r
297 UINTN Granularity;\r
298\r
299 ASSERT_LOCKED (&gMemoryLock);\r
300\r
301 if (PoolType == EfiACPIReclaimMemory ||\r
302 PoolType == EfiACPIMemoryNVS ||\r
303 PoolType == EfiRuntimeServicesCode ||\r
304 PoolType == EfiRuntimeServicesData) {\r
305\r
306 Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
307 } else {\r
308 Granularity = DEFAULT_PAGE_ALLOCATION;\r
309 }\r
310\r
311 //\r
312 // Adjust the size by the pool header & tail overhead\r
313 //\r
314\r
315 //\r
316 // Adjusting the Size to be of proper alignment so that\r
317 // we don't get an unaligned access fault later when\r
318 // pool_Tail is being initialized\r
319 //\r
320 Size = ALIGN_VARIABLE (Size);\r
321\r
322 Size += POOL_OVERHEAD;\r
323 Index = SIZE_TO_LIST(Size);\r
324 Pool = LookupPoolHead (PoolType);\r
325 if (Pool== NULL) {\r
326 return NULL;\r
327 }\r
328 Head = NULL;\r
329\r
330 //\r
331 // If allocation is over max size, just allocate pages for the request\r
332 // (slow)\r
333 //\r
334 if (Index >= SIZE_TO_LIST (Granularity)) {\r
335 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
336 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
337 Head = CoreAllocatePoolPages (PoolType, NoPages, Granularity);\r
338 goto Done;\r
339 }\r
340\r
341 //\r
342 // If there's no free pool in the proper list size, go get some more pages\r
343 //\r
344 if (IsListEmpty (&Pool->FreeList[Index])) {\r
345\r
346 Offset = LIST_TO_SIZE (Index);\r
347 MaxOffset = Granularity;\r
348\r
349 //\r
350 // Check the bins holding larger blocks, and carve one up if needed\r
351 //\r
352 while (++Index < SIZE_TO_LIST (Granularity)) {\r
353 if (!IsListEmpty (&Pool->FreeList[Index])) {\r
354 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
355 RemoveEntryList (&Free->Link);\r
356 NewPage = (VOID *) Free;\r
357 MaxOffset = LIST_TO_SIZE (Index);\r
358 goto Carve;\r
359 }\r
360 }\r
361\r
362 //\r
363 // Get another page\r
364 //\r
365 NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (Granularity), Granularity);\r
366 if (NewPage == NULL) {\r
367 goto Done;\r
368 }\r
369\r
370 //\r
371 // Serve the allocation request from the head of the allocated block\r
372 //\r
373Carve:\r
374 Head = (POOL_HEAD *) NewPage;\r
375\r
376 //\r
377 // Carve up remaining space into free pool blocks\r
378 //\r
379 Index--;\r
380 while (Offset < MaxOffset) {\r
381 ASSERT (Index < MAX_POOL_LIST);\r
382 FSize = LIST_TO_SIZE(Index);\r
383\r
384 while (Offset + FSize <= MaxOffset) {\r
385 Free = (POOL_FREE *) &NewPage[Offset];\r
386 Free->Signature = POOL_FREE_SIGNATURE;\r
387 Free->Index = (UINT32)Index;\r
388 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
389 Offset += FSize;\r
390 }\r
391 Index -= 1;\r
392 }\r
393\r
394 ASSERT (Offset == MaxOffset);\r
395 goto Done;\r
396 }\r
397\r
398 //\r
399 // Remove entry from free pool list\r
400 //\r
401 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
402 RemoveEntryList (&Free->Link);\r
403\r
404 Head = (POOL_HEAD *) Free;\r
405\r
406Done:\r
407 Buffer = NULL;\r
408\r
409 if (Head != NULL) {\r
410\r
411 //\r
412 // If we have a pool buffer, fill in the header & tail info\r
413 //\r
414 Head->Signature = POOL_HEAD_SIGNATURE;\r
415 Head->Size = Size;\r
416 Head->Type = (EFI_MEMORY_TYPE) PoolType;\r
417 Tail = HEAD_TO_TAIL (Head);\r
418 Tail->Signature = POOL_TAIL_SIGNATURE;\r
419 Tail->Size = Size;\r
420 Buffer = Head->Data;\r
421 DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);\r
422\r
423 DEBUG ((\r
424 DEBUG_POOL,\r
425 "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,\r
426 Buffer,\r
427 (UINT64)(Size - POOL_OVERHEAD),\r
428 (UINT64) Pool->Used\r
429 ));\r
430\r
431 //\r
432 // Account the allocation\r
433 //\r
434 Pool->Used += Size;\r
435\r
436 } else {\r
437 DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));\r
438 }\r
439\r
440 return Buffer;\r
441}\r
442\r
443\r
444\r
445/**\r
446 Frees pool.\r
447\r
448 @param Buffer The allocated pool entry to free\r
449\r
450 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
451 @retval EFI_SUCCESS Pool successfully freed.\r
452\r
453**/\r
454EFI_STATUS\r
455EFIAPI\r
456CoreInternalFreePool (\r
457 IN VOID *Buffer\r
458 )\r
459{\r
460 EFI_STATUS Status;\r
461\r
462 if (Buffer == NULL) {\r
463 return EFI_INVALID_PARAMETER;\r
464 }\r
465\r
466 CoreAcquireMemoryLock ();\r
467 Status = CoreFreePoolI (Buffer);\r
468 CoreReleaseMemoryLock ();\r
469 return Status;\r
470}\r
471\r
472/**\r
473 Frees pool.\r
474\r
475 @param Buffer The allocated pool entry to free\r
476\r
477 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
478 @retval EFI_SUCCESS Pool successfully freed.\r
479\r
480**/\r
481EFI_STATUS\r
482EFIAPI\r
483CoreFreePool (\r
484 IN VOID *Buffer\r
485 )\r
486{\r
487 EFI_STATUS Status;\r
488\r
489 Status = CoreInternalFreePool (Buffer);\r
490 if (!EFI_ERROR (Status)) {\r
491 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePool, (EFI_MEMORY_TYPE) 0, 0, Buffer);\r
492 }\r
493 return Status;\r
494}\r
495\r
496/**\r
497 Internal function to free a pool entry.\r
498 Caller must have the memory lock held\r
499\r
500 @param Buffer The allocated pool entry to free\r
501\r
502 @retval EFI_INVALID_PARAMETER Buffer not valid\r
503 @retval EFI_SUCCESS Buffer successfully freed.\r
504\r
505**/\r
506EFI_STATUS\r
507CoreFreePoolI (\r
508 IN VOID *Buffer\r
509 )\r
510{\r
511 POOL *Pool;\r
512 POOL_HEAD *Head;\r
513 POOL_TAIL *Tail;\r
514 POOL_FREE *Free;\r
515 UINTN Index;\r
516 UINTN NoPages;\r
517 UINTN Size;\r
518 CHAR8 *NewPage;\r
519 UINTN Offset;\r
520 BOOLEAN AllFree;\r
521 UINTN Granularity;\r
522\r
523 ASSERT(Buffer != NULL);\r
524 //\r
525 // Get the head & tail of the pool entry\r
526 //\r
527 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
528 ASSERT(Head != NULL);\r
529\r
530 if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
531 return EFI_INVALID_PARAMETER;\r
532 }\r
533\r
534 Tail = HEAD_TO_TAIL (Head);\r
535 ASSERT(Tail != NULL);\r
536\r
537 //\r
538 // Debug\r
539 //\r
540 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
541 ASSERT (Head->Size == Tail->Size);\r
542 ASSERT_LOCKED (&gMemoryLock);\r
543\r
544 if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
545 return EFI_INVALID_PARAMETER;\r
546 }\r
547\r
548 if (Head->Size != Tail->Size) {\r
549 return EFI_INVALID_PARAMETER;\r
550 }\r
551\r
552 //\r
553 // Determine the pool type and account for it\r
554 //\r
555 Size = Head->Size;\r
556 Pool = LookupPoolHead (Head->Type);\r
557 if (Pool == NULL) {\r
558 return EFI_INVALID_PARAMETER;\r
559 }\r
560 Pool->Used -= Size;\r
561 DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
562\r
563 if (Head->Type == EfiACPIReclaimMemory ||\r
564 Head->Type == EfiACPIMemoryNVS ||\r
565 Head->Type == EfiRuntimeServicesCode ||\r
566 Head->Type == EfiRuntimeServicesData) {\r
567\r
568 Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
569 } else {\r
570 Granularity = DEFAULT_PAGE_ALLOCATION;\r
571 }\r
572\r
573 //\r
574 // Determine the pool list\r
575 //\r
576 Index = SIZE_TO_LIST(Size);\r
577 DEBUG_CLEAR_MEMORY (Head, Size);\r
578\r
579 //\r
580 // If it's not on the list, it must be pool pages\r
581 //\r
582 if (Index >= SIZE_TO_LIST (Granularity)) {\r
583\r
584 //\r
585 // Return the memory pages back to free memory\r
586 //\r
587 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
588 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
589 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
590\r
591 } else {\r
592\r
593 //\r
594 // Put the pool entry onto the free pool list\r
595 //\r
596 Free = (POOL_FREE *) Head;\r
597 ASSERT(Free != NULL);\r
598 Free->Signature = POOL_FREE_SIGNATURE;\r
599 Free->Index = (UINT32)Index;\r
600 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
601\r
602 //\r
603 // See if all the pool entries in the same page as Free are freed pool\r
604 // entries\r
605 //\r
606 NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));\r
607 Free = (POOL_FREE *) &NewPage[0];\r
608 ASSERT(Free != NULL);\r
609\r
610 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
611\r
612 AllFree = TRUE;\r
613 Offset = 0;\r
614\r
615 while ((Offset < Granularity) && (AllFree)) {\r
616 Free = (POOL_FREE *) &NewPage[Offset];\r
617 ASSERT(Free != NULL);\r
618 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
619 AllFree = FALSE;\r
620 }\r
621 Offset += LIST_TO_SIZE(Free->Index);\r
622 }\r
623\r
624 if (AllFree) {\r
625\r
626 //\r
627 // All of the pool entries in the same page as Free are free pool\r
628 // entries\r
629 // Remove all of these pool entries from the free loop lists.\r
630 //\r
631 Free = (POOL_FREE *) &NewPage[0];\r
632 ASSERT(Free != NULL);\r
633 Offset = 0;\r
634\r
635 while (Offset < Granularity) {\r
636 Free = (POOL_FREE *) &NewPage[Offset];\r
637 ASSERT(Free != NULL);\r
638 RemoveEntryList (&Free->Link);\r
639 Offset += LIST_TO_SIZE(Free->Index);\r
640 }\r
641\r
642 //\r
643 // Free the page\r
644 //\r
645 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (Granularity));\r
646 }\r
647 }\r
648 }\r
649\r
650 //\r
651 // If this is an OS specific memory type, then check to see if the last\r
652 // portion of that memory type has been freed. If it has, then free the\r
653 // list entry for that memory type\r
654 //\r
655 if ((INT32)Pool->MemoryType < 0 && Pool->Used == 0) {\r
656 RemoveEntryList (&Pool->Link);\r
657 CoreFreePoolI (Pool);\r
658 }\r
659\r
660 return EFI_SUCCESS;\r
661}\r
662\r