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