git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3045 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			614 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			614 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| Copyright (c) 2006, Intel Corporation                                                         
 | |
| All rights reserved. This program and the accompanying materials                          
 | |
| are licensed and made available under the terms and conditions of the BSD License         
 | |
| which accompanies this distribution.  The full text of the license may be found at        
 | |
| http://opensource.org/licenses/bsd-license.php                                            
 | |
|                                                                                           
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
 | |
| 
 | |
| Module Name:
 | |
| 
 | |
|   pool.c
 | |
| 
 | |
| Abstract:
 | |
| 
 | |
|   EFI Memory pool management
 | |
| 
 | |
| Revision History
 | |
| 
 | |
| --*/
 | |
| 
 | |
| #include <DxeMain.h>
 | |
| 
 | |
| #define POOL_FREE_SIGNATURE   EFI_SIGNATURE_32('p','f','r','0')
 | |
| typedef struct {
 | |
|   UINT32          Signature;
 | |
|   UINT32          Index;
 | |
|   LIST_ENTRY      Link;
 | |
| } POOL_FREE;
 | |
| 
 | |
| 
 | |
| #define POOL_HEAD_SIGNATURE   EFI_SIGNATURE_32('p','h','d','0')
 | |
| typedef struct {
 | |
|   UINT32          Signature;
 | |
|   UINT32          Size;
 | |
|   EFI_MEMORY_TYPE Type;
 | |
|   UINTN           Reserved;
 | |
|   CHAR8           Data[1];
 | |
| } POOL_HEAD;
 | |
| 
 | |
| #define SIZE_OF_POOL_HEAD EFI_FIELD_OFFSET(POOL_HEAD,Data)
 | |
| 
 | |
| #define POOL_TAIL_SIGNATURE   EFI_SIGNATURE_32('p','t','a','l')
 | |
| typedef struct {
 | |
|   UINT32      Signature;
 | |
|   UINT32      Size;
 | |
| } POOL_TAIL;
 | |
| 
 | |
| 
 | |
| #define POOL_SHIFT  7
 | |
| 
 | |
| #define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))
 | |
| 
 | |
| #define HEAD_TO_TAIL(a)   \
 | |
|   ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
 | |
| 
 | |
| 
 | |
| #define SIZE_TO_LIST(a)   ((a) >> POOL_SHIFT)
 | |
| #define LIST_TO_SIZE(a)   ((a+1) << POOL_SHIFT)
 | |
| 
 | |
| #define MAX_POOL_LIST       SIZE_TO_LIST(DEFAULT_PAGE_ALLOCATION)
 | |
| 
 | |
| #define MAX_POOL_SIZE     (MAX_ADDRESS - POOL_OVERHEAD)
 | |
| 
 | |
| //
 | |
| // Globals
 | |
| //
 | |
| 
 | |
| #define POOL_SIGNATURE  EFI_SIGNATURE_32('p','l','s','t')
 | |
| typedef struct {
 | |
|     INTN             Signature;
 | |
|     UINTN            Used;
 | |
|     EFI_MEMORY_TYPE  MemoryType;
 | |
|     LIST_ENTRY       FreeList[MAX_POOL_LIST];
 | |
|     LIST_ENTRY       Link;
 | |
| } POOL; 
 | |
| 
 | |
| 
 | |
| POOL            PoolHead[EfiMaxMemoryType];
 | |
| LIST_ENTRY      PoolHeadList;
 | |
| 
 | |
| //
 | |
| //
 | |
| //
 | |
| 
 | |
| VOID
 | |
| CoreInitializePool (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Called to initialize the pool.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   None
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINTN  Type;
 | |
|   UINTN  Index;
 | |
| 
 | |
|   for (Type=0; Type < EfiMaxMemoryType; Type++) {
 | |
|     PoolHead[Type].Signature  = 0;
 | |
|     PoolHead[Type].Used       = 0;
 | |
|     PoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;
 | |
|     for (Index=0; Index < MAX_POOL_LIST; Index++) {
 | |
|         InitializeListHead (&PoolHead[Type].FreeList[Index]);
 | |
|     }
 | |
|   }
 | |
|   InitializeListHead (&PoolHeadList);
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| POOL *
 | |
| LookupPoolHead (
 | |
|   IN EFI_MEMORY_TYPE  MemoryType
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Look up pool head for specified memory type.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   MemoryType      - Memory type of which pool head is looked for
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   Pointer of Corresponding pool head.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   LIST_ENTRY      *Link;
 | |
|   POOL            *Pool;
 | |
|   UINTN           Index;
 | |
| 
 | |
|   if (MemoryType >= 0 && MemoryType < EfiMaxMemoryType) {
 | |
|     return &PoolHead[MemoryType];
 | |
|   }
 | |
| 
 | |
|   if (MemoryType < 0) {
 | |
| 
 | |
|     for (Link = PoolHeadList.ForwardLink; Link != &PoolHeadList; Link = Link->ForwardLink) {
 | |
|       Pool = CR(Link, POOL, Link, POOL_SIGNATURE);
 | |
|       if (Pool->MemoryType == MemoryType) {
 | |
|         return Pool;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));
 | |
|     if (Pool == NULL) {
 | |
|       return NULL;
 | |
|     }
 | |
| 
 | |
|     Pool->Signature = POOL_SIGNATURE;
 | |
|     Pool->Used      = 0;
 | |
|     Pool->MemoryType = MemoryType;
 | |
|     for (Index=0; Index < MAX_POOL_LIST; Index++) {
 | |
|       InitializeListHead (&Pool->FreeList[Index]);
 | |
|     }
 | |
| 
 | |
|     InsertHeadList (&PoolHeadList, &Pool->Link);
 | |
| 
 | |
|     return Pool;
 | |
|   }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
|  
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| CoreAllocatePool (
 | |
|   IN EFI_MEMORY_TYPE  PoolType,
 | |
|   IN UINTN            Size,
 | |
|   OUT VOID            **Buffer
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Allocate pool of a particular type.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   PoolType    - Type of pool to allocate
 | |
| 
 | |
|   Size        - The amount of pool to allocate
 | |
| 
 | |
|   Buffer      - The address to return a pointer to the allocated pool
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_INVALID_PARAMETER     - PoolType not valid
 | |
|   
 | |
|   EFI_OUT_OF_RESOURCES      - Size exceeds max pool size or allocation failed.  
 | |
|   
 | |
|   EFI_SUCCESS               - Pool successfully allocated.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS    Status;
 | |
| 
 | |
|   //
 | |
|   // If it's not a valid type, fail it
 | |
|   //
 | |
|   if ((PoolType >= EfiMaxMemoryType && PoolType <= 0x7fffffff) ||
 | |
|        PoolType == EfiConventionalMemory) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   
 | |
|   *Buffer = NULL;
 | |
|   
 | |
|   //
 | |
|   // If size is too large, fail it
 | |
|   // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES
 | |
|   //
 | |
|   if (Size > MAX_POOL_SIZE) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Acquire the memory lock and make the allocation
 | |
|   //
 | |
|   Status = CoreAcquireLockOrFail (&gMemoryLock);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   *Buffer = CoreAllocatePoolI (PoolType, Size);
 | |
|   CoreReleaseMemoryLock ();
 | |
|   return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
 | |
| }
 | |
| 
 | |
| 
 | |
| VOID *
 | |
| CoreAllocatePoolI (
 | |
|   IN EFI_MEMORY_TYPE  PoolType,
 | |
|   IN UINTN            Size
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Internal function to allocate pool of a particular type.
 | |
| 
 | |
|   Caller must have the memory lock held
 | |
| 
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   PoolType    - Type of pool to allocate
 | |
| 
 | |
|   Size        - The amount of pool to allocate
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   The allocate pool, or NULL
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   POOL        *Pool;
 | |
|   POOL_FREE   *Free;
 | |
|   POOL_HEAD   *Head;
 | |
|   POOL_TAIL   *Tail;
 | |
|   CHAR8       *NewPage;
 | |
|   VOID        *Buffer;
 | |
|   UINTN       Index;
 | |
|   UINTN       FSize;
 | |
|   UINTN       offset;
 | |
|   UINTN       Adjustment;
 | |
|   UINTN       NoPages;
 | |
| 
 | |
|   ASSERT_LOCKED (&gMemoryLock);
 | |
| 
 | |
|   //
 | |
|   // Adjust the size by the pool header & tail overhead
 | |
|   //
 | |
|   
 | |
|   //
 | |
|   // Adjusting the Size to be of proper alignment so that
 | |
|   // we don't get an unaligned access fault later when
 | |
|   // pool_Tail is being initialized
 | |
|   //
 | |
|   ALIGN_VARIABLE (Size, Adjustment);
 | |
| 
 | |
|   Size += POOL_OVERHEAD;
 | |
|   Index = SIZE_TO_LIST(Size);
 | |
|   Pool = LookupPoolHead (PoolType);
 | |
|   if (Pool== NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
|   Head = NULL;
 | |
| 
 | |
|   //
 | |
|   // If allocation is over max size, just allocate pages for the request
 | |
|   // (slow)
 | |
|   //
 | |
|   if (Index >= MAX_POOL_LIST) {
 | |
|     NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;
 | |
|     NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);
 | |
|     Head = CoreAllocatePoolPages (PoolType, NoPages, DEFAULT_PAGE_ALLOCATION);
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If there's no free pool in the proper list size, go get some more pages
 | |
|   //
 | |
|   if (IsListEmpty (&Pool->FreeList[Index])) {
 | |
| 
 | |
|     //
 | |
|     // Get another page
 | |
|     //
 | |
|     NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);
 | |
|     if (NewPage == NULL) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Carve up new page into free pool blocks
 | |
|     //
 | |
|     offset = 0;
 | |
|     while (offset < DEFAULT_PAGE_ALLOCATION) {
 | |
|       ASSERT (Index < MAX_POOL_LIST);
 | |
|       FSize = LIST_TO_SIZE(Index);
 | |
| 
 | |
|       while (offset + FSize <= DEFAULT_PAGE_ALLOCATION) {
 | |
|         Free = (POOL_FREE *) &NewPage[offset];          
 | |
|         Free->Signature = POOL_FREE_SIGNATURE;
 | |
|         Free->Index     = (UINT32)Index;
 | |
|         InsertHeadList (&Pool->FreeList[Index], &Free->Link);
 | |
|         offset += FSize;
 | |
|       }
 | |
| 
 | |
|       Index -= 1;
 | |
|     }
 | |
| 
 | |
|     ASSERT (offset == DEFAULT_PAGE_ALLOCATION);
 | |
|     Index = SIZE_TO_LIST(Size);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Remove entry from free pool list
 | |
|   //
 | |
|   Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
 | |
|   RemoveEntryList (&Free->Link);
 | |
| 
 | |
|   Head = (POOL_HEAD *) Free;
 | |
| 
 | |
| Done:
 | |
|   Buffer = NULL;
 | |
| 
 | |
|   if (Head != NULL) {
 | |
|     
 | |
|     //
 | |
|     // If we have a pool buffer, fill in the header & tail info
 | |
|     //
 | |
|     Head->Signature = POOL_HEAD_SIGNATURE;
 | |
|     Head->Size      = (UINT32) Size;
 | |
|     Head->Type      = (EFI_MEMORY_TYPE) PoolType;
 | |
|     Tail            = HEAD_TO_TAIL (Head);
 | |
|     Tail->Signature = POOL_TAIL_SIGNATURE;
 | |
|     Tail->Size      = (UINT32) Size;
 | |
|     Buffer          = Head->Data;
 | |
|     DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);
 | |
| 
 | |
|     DEBUG (
 | |
|       (EFI_D_POOL,
 | |
|       "AllcocatePoolI: Type %x, Addr %x (len %x) %,d\n",
 | |
|        PoolType, 
 | |
|        Buffer, 
 | |
|        Size - POOL_OVERHEAD, 
 | |
|       Pool->Used)
 | |
|       );
 | |
| 
 | |
|     //
 | |
|     // Account the allocation
 | |
|     //
 | |
|     Pool->Used += Size;
 | |
| 
 | |
|   } else {
 | |
|     DEBUG ((EFI_D_ERROR | EFI_D_POOL, "AllocatePool: failed to allocate %d bytes\n", Size));
 | |
|   }
 | |
| 
 | |
|   return Buffer;
 | |
| }
 | |
|   
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| CoreFreePool (
 | |
|   IN VOID        *Buffer
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Frees pool.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Buffer      - The allocated pool entry to free
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_INVALID_PARAMETER   - Buffer is not a valid value.
 | |
|   
 | |
|   EFI_SUCCESS             - Pool successfully freed.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
| 
 | |
|   if (NULL == Buffer) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   CoreAcquireMemoryLock ();
 | |
|   Status = CoreFreePoolI (Buffer);
 | |
|   CoreReleaseMemoryLock ();
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| CoreFreePoolI (
 | |
|   IN VOID       *Buffer
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Internal function to free a pool entry.
 | |
| 
 | |
|   Caller must have the memory lock held
 | |
| 
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Buffer      - The allocated pool entry to free
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_INVALID_PARAMETER     - Buffer not valid
 | |
|   
 | |
|   EFI_SUCCESS               - Buffer successfully freed.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   POOL        *Pool;
 | |
|   POOL_HEAD   *Head;
 | |
|   POOL_TAIL   *Tail;
 | |
|   POOL_FREE   *Free;
 | |
|   UINTN       Index;
 | |
|   UINTN       NoPages;
 | |
|   UINTN       Size;
 | |
|   CHAR8       *NewPage;
 | |
|   UINTN       FSize;
 | |
|   UINTN       offset;
 | |
|   BOOLEAN     AllFree;
 | |
| 
 | |
|   ASSERT(NULL != Buffer);
 | |
|   //
 | |
|   // Get the head & tail of the pool entry
 | |
|   //
 | |
|   Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);
 | |
|   ASSERT(NULL != Head);
 | |
| 
 | |
|   if (Head->Signature != POOL_HEAD_SIGNATURE) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Tail = HEAD_TO_TAIL (Head);
 | |
|   ASSERT(NULL != Tail);
 | |
| 
 | |
|   //
 | |
|   // Debug
 | |
|   //
 | |
|   ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);
 | |
|   ASSERT (Head->Size == Tail->Size);
 | |
|   ASSERT_LOCKED (&gMemoryLock);
 | |
| 
 | |
|   if (Tail->Signature != POOL_TAIL_SIGNATURE) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (Head->Size != Tail->Size) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Determine the pool type and account for it
 | |
|   //
 | |
|   Size = Head->Size;
 | |
|   Pool = LookupPoolHead (Head->Type);
 | |
|   if (Pool == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   Pool->Used -= Size;
 | |
|   DEBUG ((EFI_D_POOL, "FreePool: %x (len %x) %,d\n", Head->Data, Head->Size - POOL_OVERHEAD, Pool->Used));
 | |
| 
 | |
|   //
 | |
|   // Determine the pool list 
 | |
|   //
 | |
|   Index = SIZE_TO_LIST(Size);
 | |
|   DEBUG_CLEAR_MEMORY (Head, Size);
 | |
| 
 | |
|   //
 | |
|   // If it's not on the list, it must be pool pages
 | |
|   //
 | |
|   if (Index >= MAX_POOL_LIST) {
 | |
| 
 | |
|     //
 | |
|     // Return the memory pages back to free memory
 | |
|     //
 | |
|     NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;
 | |
|     NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);
 | |
|     CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);
 | |
| 
 | |
|   } else {
 | |
| 
 | |
|     //
 | |
|     // Put the pool entry onto the free pool list
 | |
|     //
 | |
|     Free = (POOL_FREE *) Head;
 | |
|     ASSERT(NULL != Free);
 | |
|     Free->Signature = POOL_FREE_SIGNATURE;
 | |
|     Free->Index     = (UINT32)Index;
 | |
|     InsertHeadList (&Pool->FreeList[Index], &Free->Link);
 | |
| 
 | |
|     //
 | |
|     // See if all the pool entries in the same page as Free are freed pool 
 | |
|     // entries
 | |
|     //
 | |
|     NewPage = (CHAR8 *)((UINTN)Free & ~((DEFAULT_PAGE_ALLOCATION) -1));
 | |
|     Free = (POOL_FREE *) &NewPage[0];
 | |
|     ASSERT(NULL != Free);
 | |
| 
 | |
|     if (Free->Signature == POOL_FREE_SIGNATURE) {
 | |
| 
 | |
|       Index = Free->Index;
 | |
| 
 | |
|       AllFree = TRUE;
 | |
|       offset = 0;
 | |
|       
 | |
|       while ((offset < DEFAULT_PAGE_ALLOCATION) && (AllFree)) {
 | |
|         FSize = LIST_TO_SIZE(Index);
 | |
|         while (offset + FSize <= DEFAULT_PAGE_ALLOCATION) {
 | |
|           Free = (POOL_FREE *) &NewPage[offset];
 | |
|           ASSERT(NULL != Free);
 | |
|           if (Free->Signature != POOL_FREE_SIGNATURE) {
 | |
|             AllFree = FALSE;
 | |
|           }
 | |
|           offset += FSize;
 | |
|         }
 | |
|         Index -= 1;
 | |
|       }
 | |
| 
 | |
|       if (AllFree) {
 | |
| 
 | |
|         //
 | |
|         // All of the pool entries in the same page as Free are free pool 
 | |
|         // entries
 | |
|         // Remove all of these pool entries from the free loop lists.
 | |
|         //
 | |
|         Free = (POOL_FREE *) &NewPage[0];
 | |
|         ASSERT(NULL != Free);
 | |
|         Index = Free->Index;
 | |
|         offset = 0;
 | |
|         
 | |
|         while (offset < DEFAULT_PAGE_ALLOCATION) {
 | |
|           FSize = LIST_TO_SIZE(Index);
 | |
|           while (offset + FSize <= DEFAULT_PAGE_ALLOCATION) {
 | |
|             Free = (POOL_FREE *) &NewPage[offset];
 | |
|             ASSERT(NULL != Free);
 | |
|             RemoveEntryList (&Free->Link);
 | |
|             offset += FSize;
 | |
|           }
 | |
|           Index -= 1;
 | |
|         }
 | |
| 
 | |
|         //
 | |
|         // Free the page
 | |
|         //
 | |
|         CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION));
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If this is an OS specific memory type, then check to see if the last 
 | |
|   // portion of that memory type has been freed.  If it has, then free the
 | |
|   // list entry for that memory type
 | |
|   //
 | |
|   if (Pool->MemoryType < 0 && Pool->Used == 0) {
 | |
|     RemoveEntryList (&Pool->Link);
 | |
|     CoreFreePoolI (Pool);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 |