3 UEFI Memory pool management functions.
5 Copyright (c) 2006 - 2008, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #define POOL_FREE_SIGNATURE EFI_SIGNATURE_32('p','f','r','0')
26 #define POOL_HEAD_SIGNATURE EFI_SIGNATURE_32('p','h','d','0')
35 #define SIZE_OF_POOL_HEAD EFI_FIELD_OFFSET(POOL_HEAD,Data)
37 #define POOL_TAIL_SIGNATURE EFI_SIGNATURE_32('p','t','a','l')
46 #define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))
48 #define HEAD_TO_TAIL(a) \
49 ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
52 #define SIZE_TO_LIST(a) ((a) >> POOL_SHIFT)
53 #define LIST_TO_SIZE(a) ((a+1) << POOL_SHIFT)
55 #define MAX_POOL_LIST SIZE_TO_LIST(DEFAULT_PAGE_ALLOCATION)
57 #define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)
63 #define POOL_SIGNATURE EFI_SIGNATURE_32('p','l','s','t')
67 EFI_MEMORY_TYPE MemoryType
;
68 LIST_ENTRY FreeList
[MAX_POOL_LIST
];
73 POOL PoolHead
[EfiMaxMemoryType
];
74 LIST_ENTRY PoolHeadList
;
88 Called to initialize the pool.
103 for (Type
=0; Type
< EfiMaxMemoryType
; Type
++) {
104 PoolHead
[Type
].Signature
= 0;
105 PoolHead
[Type
].Used
= 0;
106 PoolHead
[Type
].MemoryType
= (EFI_MEMORY_TYPE
) Type
;
107 for (Index
=0; Index
< MAX_POOL_LIST
; Index
++) {
108 InitializeListHead (&PoolHead
[Type
].FreeList
[Index
]);
111 InitializeListHead (&PoolHeadList
);
117 IN EFI_MEMORY_TYPE MemoryType
123 Look up pool head for specified memory type.
127 MemoryType - Memory type of which pool head is looked for
131 Pointer of Corresponding pool head.
139 if (MemoryType
>= 0 && MemoryType
< EfiMaxMemoryType
) {
140 return &PoolHead
[MemoryType
];
143 if (MemoryType
< 0) {
145 for (Link
= PoolHeadList
.ForwardLink
; Link
!= &PoolHeadList
; Link
= Link
->ForwardLink
) {
146 Pool
= CR(Link
, POOL
, Link
, POOL_SIGNATURE
);
147 if (Pool
->MemoryType
== MemoryType
) {
152 Pool
= CoreAllocatePoolI (EfiBootServicesData
, sizeof (POOL
));
157 Pool
->Signature
= POOL_SIGNATURE
;
159 Pool
->MemoryType
= MemoryType
;
160 for (Index
=0; Index
< MAX_POOL_LIST
; Index
++) {
161 InitializeListHead (&Pool
->FreeList
[Index
]);
164 InsertHeadList (&PoolHeadList
, &Pool
->Link
);
177 IN EFI_MEMORY_TYPE PoolType
,
185 Allocate pool of a particular type.
189 PoolType - Type of pool to allocate
191 Size - The amount of pool to allocate
193 Buffer - The address to return a pointer to the allocated pool
197 EFI_INVALID_PARAMETER - PoolType not valid
199 EFI_OUT_OF_RESOURCES - Size exceeds max pool size or allocation failed.
201 EFI_SUCCESS - Pool successfully allocated.
208 // If it's not a valid type, fail it
210 if ((PoolType
>= EfiMaxMemoryType
&& PoolType
<= 0x7fffffff) ||
211 PoolType
== EfiConventionalMemory
) {
212 return EFI_INVALID_PARAMETER
;
218 // If size is too large, fail it
219 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES
221 if (Size
> MAX_POOL_SIZE
) {
222 return EFI_OUT_OF_RESOURCES
;
226 // Acquire the memory lock and make the allocation
228 Status
= CoreAcquireLockOrFail (&gMemoryLock
);
229 if (EFI_ERROR (Status
)) {
230 return EFI_OUT_OF_RESOURCES
;
233 *Buffer
= CoreAllocatePoolI (PoolType
, Size
);
234 CoreReleaseMemoryLock ();
235 return (*Buffer
!= NULL
) ? EFI_SUCCESS
: EFI_OUT_OF_RESOURCES
;
241 IN EFI_MEMORY_TYPE PoolType
,
248 Internal function to allocate pool of a particular type.
250 Caller must have the memory lock held
255 PoolType - Type of pool to allocate
257 Size - The amount of pool to allocate
261 The allocate pool, or NULL
277 ASSERT_LOCKED (&gMemoryLock
);
280 // Adjust the size by the pool header & tail overhead
284 // Adjusting the Size to be of proper alignment so that
285 // we don't get an unaligned access fault later when
286 // pool_Tail is being initialized
288 ALIGN_VARIABLE (Size
, Adjustment
);
290 Size
+= POOL_OVERHEAD
;
291 Index
= SIZE_TO_LIST(Size
);
292 Pool
= LookupPoolHead (PoolType
);
299 // If allocation is over max size, just allocate pages for the request
302 if (Index
>= MAX_POOL_LIST
) {
303 NoPages
= EFI_SIZE_TO_PAGES(Size
) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
) - 1;
304 NoPages
&= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
) - 1);
305 Head
= CoreAllocatePoolPages (PoolType
, NoPages
, DEFAULT_PAGE_ALLOCATION
);
310 // If there's no free pool in the proper list size, go get some more pages
312 if (IsListEmpty (&Pool
->FreeList
[Index
])) {
317 NewPage
= CoreAllocatePoolPages(PoolType
, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
), DEFAULT_PAGE_ALLOCATION
);
318 if (NewPage
== NULL
) {
323 // Carve up new page into free pool blocks
326 while (offset
< DEFAULT_PAGE_ALLOCATION
) {
327 ASSERT (Index
< MAX_POOL_LIST
);
328 FSize
= LIST_TO_SIZE(Index
);
330 while (offset
+ FSize
<= DEFAULT_PAGE_ALLOCATION
) {
331 Free
= (POOL_FREE
*) &NewPage
[offset
];
332 Free
->Signature
= POOL_FREE_SIGNATURE
;
333 Free
->Index
= (UINT32
)Index
;
334 InsertHeadList (&Pool
->FreeList
[Index
], &Free
->Link
);
341 ASSERT (offset
== DEFAULT_PAGE_ALLOCATION
);
342 Index
= SIZE_TO_LIST(Size
);
346 // Remove entry from free pool list
348 Free
= CR (Pool
->FreeList
[Index
].ForwardLink
, POOL_FREE
, Link
, POOL_FREE_SIGNATURE
);
349 RemoveEntryList (&Free
->Link
);
351 Head
= (POOL_HEAD
*) Free
;
359 // If we have a pool buffer, fill in the header & tail info
361 Head
->Signature
= POOL_HEAD_SIGNATURE
;
362 Head
->Size
= (UINT32
) Size
;
363 Head
->Type
= (EFI_MEMORY_TYPE
) PoolType
;
364 Tail
= HEAD_TO_TAIL (Head
);
365 Tail
->Signature
= POOL_TAIL_SIGNATURE
;
366 Tail
->Size
= (UINT32
) Size
;
368 DEBUG_CLEAR_MEMORY (Buffer
, Size
- POOL_OVERHEAD
);
372 "AllocatePoolI: Type %x, Addr %x (len %x) %,d\n",
375 Size
- POOL_OVERHEAD
,
380 // Account the allocation
385 DEBUG ((EFI_D_ERROR
| EFI_D_POOL
, "AllocatePool: failed to allocate %d bytes\n", Size
));
406 Buffer - The allocated pool entry to free
410 EFI_INVALID_PARAMETER - Buffer is not a valid value.
412 EFI_SUCCESS - Pool successfully freed.
418 if (NULL
== Buffer
) {
419 return EFI_INVALID_PARAMETER
;
422 CoreAcquireMemoryLock ();
423 Status
= CoreFreePoolI (Buffer
);
424 CoreReleaseMemoryLock ();
437 Internal function to free a pool entry.
439 Caller must have the memory lock held
444 Buffer - The allocated pool entry to free
448 EFI_INVALID_PARAMETER - Buffer not valid
450 EFI_SUCCESS - Buffer successfully freed.
466 ASSERT(NULL
!= Buffer
);
468 // Get the head & tail of the pool entry
470 Head
= CR (Buffer
, POOL_HEAD
, Data
, POOL_HEAD_SIGNATURE
);
471 ASSERT(NULL
!= Head
);
473 if (Head
->Signature
!= POOL_HEAD_SIGNATURE
) {
474 return EFI_INVALID_PARAMETER
;
477 Tail
= HEAD_TO_TAIL (Head
);
478 ASSERT(NULL
!= Tail
);
483 ASSERT (Tail
->Signature
== POOL_TAIL_SIGNATURE
);
484 ASSERT (Head
->Size
== Tail
->Size
);
485 ASSERT_LOCKED (&gMemoryLock
);
487 if (Tail
->Signature
!= POOL_TAIL_SIGNATURE
) {
488 return EFI_INVALID_PARAMETER
;
491 if (Head
->Size
!= Tail
->Size
) {
492 return EFI_INVALID_PARAMETER
;
496 // Determine the pool type and account for it
499 Pool
= LookupPoolHead (Head
->Type
);
501 return EFI_INVALID_PARAMETER
;
504 DEBUG ((EFI_D_POOL
, "FreePool: %x (len %x) %,d\n", Head
->Data
, Head
->Size
- POOL_OVERHEAD
, Pool
->Used
));
507 // Determine the pool list
509 Index
= SIZE_TO_LIST(Size
);
510 DEBUG_CLEAR_MEMORY (Head
, Size
);
513 // If it's not on the list, it must be pool pages
515 if (Index
>= MAX_POOL_LIST
) {
518 // Return the memory pages back to free memory
520 NoPages
= EFI_SIZE_TO_PAGES(Size
) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
) - 1;
521 NoPages
&= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
) - 1);
522 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Head
, NoPages
);
527 // Put the pool entry onto the free pool list
529 Free
= (POOL_FREE
*) Head
;
530 ASSERT(NULL
!= Free
);
531 Free
->Signature
= POOL_FREE_SIGNATURE
;
532 Free
->Index
= (UINT32
)Index
;
533 InsertHeadList (&Pool
->FreeList
[Index
], &Free
->Link
);
536 // See if all the pool entries in the same page as Free are freed pool
539 NewPage
= (CHAR8
*)((UINTN
)Free
& ~((DEFAULT_PAGE_ALLOCATION
) -1));
540 Free
= (POOL_FREE
*) &NewPage
[0];
541 ASSERT(NULL
!= Free
);
543 if (Free
->Signature
== POOL_FREE_SIGNATURE
) {
550 while ((offset
< DEFAULT_PAGE_ALLOCATION
) && (AllFree
)) {
551 FSize
= LIST_TO_SIZE(Index
);
552 while (offset
+ FSize
<= DEFAULT_PAGE_ALLOCATION
) {
553 Free
= (POOL_FREE
*) &NewPage
[offset
];
554 ASSERT(NULL
!= Free
);
555 if (Free
->Signature
!= POOL_FREE_SIGNATURE
) {
566 // All of the pool entries in the same page as Free are free pool
568 // Remove all of these pool entries from the free loop lists.
570 Free
= (POOL_FREE
*) &NewPage
[0];
571 ASSERT(NULL
!= Free
);
575 while (offset
< DEFAULT_PAGE_ALLOCATION
) {
576 FSize
= LIST_TO_SIZE(Index
);
577 while (offset
+ FSize
<= DEFAULT_PAGE_ALLOCATION
) {
578 Free
= (POOL_FREE
*) &NewPage
[offset
];
579 ASSERT(NULL
!= Free
);
580 RemoveEntryList (&Free
->Link
);
589 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS
) (UINTN
)NewPage
, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
));
595 // If this is an OS specific memory type, then check to see if the last
596 // portion of that memory type has been freed. If it has, then free the
597 // list entry for that memory type
599 if (Pool
->MemoryType
< 0 && Pool
->Used
== 0) {
600 RemoveEntryList (&Pool
->Link
);
601 CoreFreePoolI (Pool
);