2 UEFI Memory pool management functions.
4 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #define POOL_FREE_SIGNATURE EFI_SIGNATURE_32('p','f','r','0')
25 #define POOL_HEAD_SIGNATURE EFI_SIGNATURE_32('p','h','d','0')
34 #define SIZE_OF_POOL_HEAD EFI_FIELD_OFFSET(POOL_HEAD,Data)
36 #define POOL_TAIL_SIGNATURE EFI_SIGNATURE_32('p','t','a','l')
45 #define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))
47 #define HEAD_TO_TAIL(a) \
48 ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
51 #define SIZE_TO_LIST(a) ((a) >> POOL_SHIFT)
52 #define LIST_TO_SIZE(a) ((a+1) << POOL_SHIFT)
54 #define MAX_POOL_LIST SIZE_TO_LIST(DEFAULT_PAGE_ALLOCATION)
56 #define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)
62 #define POOL_SIGNATURE EFI_SIGNATURE_32('p','l','s','t')
66 EFI_MEMORY_TYPE MemoryType
;
67 LIST_ENTRY FreeList
[MAX_POOL_LIST
];
72 POOL PoolHead
[EfiMaxMemoryType
];
73 LIST_ENTRY PoolHeadList
;
81 Called to initialize the pool.
92 for (Type
=0; Type
< EfiMaxMemoryType
; Type
++) {
93 PoolHead
[Type
].Signature
= 0;
94 PoolHead
[Type
].Used
= 0;
95 PoolHead
[Type
].MemoryType
= (EFI_MEMORY_TYPE
) Type
;
96 for (Index
=0; Index
< MAX_POOL_LIST
; Index
++) {
97 InitializeListHead (&PoolHead
[Type
].FreeList
[Index
]);
100 InitializeListHead (&PoolHeadList
);
105 Look up pool head for specified memory type.
107 @param MemoryType Memory type of which pool head is looked for
109 @return Pointer of Corresponding pool head.
114 IN EFI_MEMORY_TYPE MemoryType
121 if (MemoryType
>= 0 && MemoryType
< EfiMaxMemoryType
) {
122 return &PoolHead
[MemoryType
];
125 if (MemoryType
< 0) {
127 for (Link
= PoolHeadList
.ForwardLink
; Link
!= &PoolHeadList
; Link
= Link
->ForwardLink
) {
128 Pool
= CR(Link
, POOL
, Link
, POOL_SIGNATURE
);
129 if (Pool
->MemoryType
== MemoryType
) {
134 Pool
= CoreAllocatePoolI (EfiBootServicesData
, sizeof (POOL
));
139 Pool
->Signature
= POOL_SIGNATURE
;
141 Pool
->MemoryType
= MemoryType
;
142 for (Index
=0; Index
< MAX_POOL_LIST
; Index
++) {
143 InitializeListHead (&Pool
->FreeList
[Index
]);
146 InsertHeadList (&PoolHeadList
, &Pool
->Link
);
158 Allocate pool of a particular type.
160 @param PoolType Type of pool to allocate
161 @param Size The amount of pool to allocate
162 @param Buffer The address to return a pointer to the allocated
165 @retval EFI_INVALID_PARAMETER PoolType not valid
166 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
167 @retval EFI_SUCCESS Pool successfully allocated.
173 IN EFI_MEMORY_TYPE PoolType
,
181 // If it's not a valid type, fail it
183 if ((PoolType
>= EfiMaxMemoryType
&& PoolType
<= 0x7fffffff) ||
184 PoolType
== EfiConventionalMemory
) {
185 return EFI_INVALID_PARAMETER
;
191 // If size is too large, fail it
192 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES
194 if (Size
> MAX_POOL_SIZE
) {
195 return EFI_OUT_OF_RESOURCES
;
199 // Acquire the memory lock and make the allocation
201 Status
= CoreAcquireLockOrFail (&gMemoryLock
);
202 if (EFI_ERROR (Status
)) {
203 return EFI_OUT_OF_RESOURCES
;
206 *Buffer
= CoreAllocatePoolI (PoolType
, Size
);
207 CoreReleaseMemoryLock ();
208 return (*Buffer
!= NULL
) ? EFI_SUCCESS
: EFI_OUT_OF_RESOURCES
;
214 Internal function to allocate pool of a particular type.
215 Caller must have the memory lock held
217 @param PoolType Type of pool to allocate
218 @param Size The amount of pool to allocate
220 @return The allocate pool, or NULL
225 IN EFI_MEMORY_TYPE PoolType
,
241 ASSERT_LOCKED (&gMemoryLock
);
244 // Adjust the size by the pool header & tail overhead
248 // Adjusting the Size to be of proper alignment so that
249 // we don't get an unaligned access fault later when
250 // pool_Tail is being initialized
252 ALIGN_VARIABLE (Size
, Adjustment
);
254 Size
+= POOL_OVERHEAD
;
255 Index
= SIZE_TO_LIST(Size
);
256 Pool
= LookupPoolHead (PoolType
);
263 // If allocation is over max size, just allocate pages for the request
266 if (Index
>= MAX_POOL_LIST
) {
267 NoPages
= EFI_SIZE_TO_PAGES(Size
) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
) - 1;
268 NoPages
&= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
) - 1);
269 Head
= CoreAllocatePoolPages (PoolType
, NoPages
, DEFAULT_PAGE_ALLOCATION
);
274 // If there's no free pool in the proper list size, go get some more pages
276 if (IsListEmpty (&Pool
->FreeList
[Index
])) {
281 NewPage
= CoreAllocatePoolPages(PoolType
, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
), DEFAULT_PAGE_ALLOCATION
);
282 if (NewPage
== NULL
) {
287 // Carve up new page into free pool blocks
290 while (Offset
< DEFAULT_PAGE_ALLOCATION
) {
291 ASSERT (Index
< MAX_POOL_LIST
);
292 FSize
= LIST_TO_SIZE(Index
);
294 while (Offset
+ FSize
<= DEFAULT_PAGE_ALLOCATION
) {
295 Free
= (POOL_FREE
*) &NewPage
[Offset
];
296 Free
->Signature
= POOL_FREE_SIGNATURE
;
297 Free
->Index
= (UINT32
)Index
;
298 InsertHeadList (&Pool
->FreeList
[Index
], &Free
->Link
);
305 ASSERT (Offset
== DEFAULT_PAGE_ALLOCATION
);
306 Index
= SIZE_TO_LIST(Size
);
310 // Remove entry from free pool list
312 Free
= CR (Pool
->FreeList
[Index
].ForwardLink
, POOL_FREE
, Link
, POOL_FREE_SIGNATURE
);
313 RemoveEntryList (&Free
->Link
);
315 Head
= (POOL_HEAD
*) Free
;
323 // If we have a pool buffer, fill in the header & tail info
325 Head
->Signature
= POOL_HEAD_SIGNATURE
;
326 Head
->Size
= (UINT32
) Size
;
327 Head
->Type
= (EFI_MEMORY_TYPE
) PoolType
;
328 Tail
= HEAD_TO_TAIL (Head
);
329 Tail
->Signature
= POOL_TAIL_SIGNATURE
;
330 Tail
->Size
= (UINT32
) Size
;
332 DEBUG_CLEAR_MEMORY (Buffer
, Size
- POOL_OVERHEAD
);
336 "AllocatePoolI: Type %x, Addr %x (len %x) %,d\n",
339 Size
- POOL_OVERHEAD
,
344 // Account the allocation
349 DEBUG ((DEBUG_ERROR
| DEBUG_POOL
, "AllocatePool: failed to allocate %d bytes\n", Size
));
361 @param Buffer The allocated pool entry to free
363 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
364 @retval EFI_SUCCESS Pool successfully freed.
375 if (NULL
== Buffer
) {
376 return EFI_INVALID_PARAMETER
;
379 CoreAcquireMemoryLock ();
380 Status
= CoreFreePoolI (Buffer
);
381 CoreReleaseMemoryLock ();
388 Internal function to free a pool entry.
389 Caller must have the memory lock held
391 @param Buffer The allocated pool entry to free
393 @retval EFI_INVALID_PARAMETER Buffer not valid
394 @retval EFI_SUCCESS Buffer successfully freed.
414 ASSERT(NULL
!= Buffer
);
416 // Get the head & tail of the pool entry
418 Head
= CR (Buffer
, POOL_HEAD
, Data
, POOL_HEAD_SIGNATURE
);
419 ASSERT(NULL
!= Head
);
421 if (Head
->Signature
!= POOL_HEAD_SIGNATURE
) {
422 return EFI_INVALID_PARAMETER
;
425 Tail
= HEAD_TO_TAIL (Head
);
426 ASSERT(NULL
!= Tail
);
431 ASSERT (Tail
->Signature
== POOL_TAIL_SIGNATURE
);
432 ASSERT (Head
->Size
== Tail
->Size
);
433 ASSERT_LOCKED (&gMemoryLock
);
435 if (Tail
->Signature
!= POOL_TAIL_SIGNATURE
) {
436 return EFI_INVALID_PARAMETER
;
439 if (Head
->Size
!= Tail
->Size
) {
440 return EFI_INVALID_PARAMETER
;
444 // Determine the pool type and account for it
447 Pool
= LookupPoolHead (Head
->Type
);
449 return EFI_INVALID_PARAMETER
;
452 DEBUG ((DEBUG_POOL
, "FreePool: %x (len %x) %,d\n", Head
->Data
, Head
->Size
- POOL_OVERHEAD
, Pool
->Used
));
455 // Determine the pool list
457 Index
= SIZE_TO_LIST(Size
);
458 DEBUG_CLEAR_MEMORY (Head
, Size
);
461 // If it's not on the list, it must be pool pages
463 if (Index
>= MAX_POOL_LIST
) {
466 // Return the memory pages back to free memory
468 NoPages
= EFI_SIZE_TO_PAGES(Size
) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
) - 1;
469 NoPages
&= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
) - 1);
470 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Head
, NoPages
);
475 // Put the pool entry onto the free pool list
477 Free
= (POOL_FREE
*) Head
;
478 ASSERT(NULL
!= Free
);
479 Free
->Signature
= POOL_FREE_SIGNATURE
;
480 Free
->Index
= (UINT32
)Index
;
481 InsertHeadList (&Pool
->FreeList
[Index
], &Free
->Link
);
484 // See if all the pool entries in the same page as Free are freed pool
487 NewPage
= (CHAR8
*)((UINTN
)Free
& ~((DEFAULT_PAGE_ALLOCATION
) -1));
488 Free
= (POOL_FREE
*) &NewPage
[0];
489 ASSERT(NULL
!= Free
);
491 if (Free
->Signature
== POOL_FREE_SIGNATURE
) {
498 while ((Offset
< DEFAULT_PAGE_ALLOCATION
) && (AllFree
)) {
499 FSize
= LIST_TO_SIZE(Index
);
500 while (Offset
+ FSize
<= DEFAULT_PAGE_ALLOCATION
) {
501 Free
= (POOL_FREE
*) &NewPage
[Offset
];
502 ASSERT(NULL
!= Free
);
503 if (Free
->Signature
!= POOL_FREE_SIGNATURE
) {
514 // All of the pool entries in the same page as Free are free pool
516 // Remove all of these pool entries from the free loop lists.
518 Free
= (POOL_FREE
*) &NewPage
[0];
519 ASSERT(NULL
!= Free
);
523 while (Offset
< DEFAULT_PAGE_ALLOCATION
) {
524 FSize
= LIST_TO_SIZE(Index
);
525 while (Offset
+ FSize
<= DEFAULT_PAGE_ALLOCATION
) {
526 Free
= (POOL_FREE
*) &NewPage
[Offset
];
527 ASSERT(NULL
!= Free
);
528 RemoveEntryList (&Free
->Link
);
537 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS
) (UINTN
)NewPage
, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
));
543 // If this is an OS specific memory type, then check to see if the last
544 // portion of that memory type has been freed. If it has, then free the
545 // list entry for that memory type
547 if (Pool
->MemoryType
< 0 && Pool
->Used
== 0) {
548 RemoveEntryList (&Pool
->Link
);
549 CoreFreePoolI (Pool
);