3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 EFI Memory pool management
26 #define POOL_FREE_SIGNATURE EFI_SIGNATURE_32('p','f','r','0')
34 #define POOL_HEAD_SIGNATURE EFI_SIGNATURE_32('p','h','d','0')
43 #define SIZE_OF_POOL_HEAD EFI_FIELD_OFFSET(POOL_HEAD,Data)
45 #define POOL_TAIL_SIGNATURE EFI_SIGNATURE_32('p','t','a','l')
54 #define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))
56 #define HEAD_TO_TAIL(a) \
57 ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
60 #define SIZE_TO_LIST(a) ((a) >> POOL_SHIFT)
61 #define LIST_TO_SIZE(a) ((a+1) << POOL_SHIFT)
63 #define MAX_POOL_LIST SIZE_TO_LIST(DEFAULT_PAGE_ALLOCATION)
65 #define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)
71 #define POOL_SIGNATURE EFI_SIGNATURE_32('p','l','s','t')
75 EFI_MEMORY_TYPE MemoryType
;
76 LIST_ENTRY FreeList
[MAX_POOL_LIST
];
81 POOL PoolHead
[EfiMaxMemoryType
];
82 LIST_ENTRY PoolHeadList
;
96 Called to initialize the pool.
111 for (Type
=0; Type
< EfiMaxMemoryType
; Type
++) {
112 PoolHead
[Type
].Signature
= 0;
113 PoolHead
[Type
].Used
= 0;
114 PoolHead
[Type
].MemoryType
= (EFI_MEMORY_TYPE
) Type
;
115 for (Index
=0; Index
< MAX_POOL_LIST
; Index
++) {
116 InitializeListHead (&PoolHead
[Type
].FreeList
[Index
]);
119 InitializeListHead (&PoolHeadList
);
125 IN EFI_MEMORY_TYPE MemoryType
131 Look up pool head for specified memory type.
135 MemoryType - Memory type of which pool head is looked for
139 Pointer of Corresponding pool head.
147 if (MemoryType
>= 0 && MemoryType
< EfiMaxMemoryType
) {
148 return &PoolHead
[MemoryType
];
151 if (MemoryType
< 0) {
153 for (Link
= PoolHeadList
.ForwardLink
; Link
!= &PoolHeadList
; Link
= Link
->ForwardLink
) {
154 Pool
= CR(Link
, POOL
, Link
, POOL_SIGNATURE
);
155 if (Pool
->MemoryType
== MemoryType
) {
160 Pool
= CoreAllocatePoolI (EfiBootServicesData
, sizeof (POOL
));
165 Pool
->Signature
= POOL_SIGNATURE
;
167 Pool
->MemoryType
= MemoryType
;
168 for (Index
=0; Index
< MAX_POOL_LIST
; Index
++) {
169 InitializeListHead (&Pool
->FreeList
[Index
]);
172 InsertHeadList (&PoolHeadList
, &Pool
->Link
);
185 IN EFI_MEMORY_TYPE PoolType
,
193 Allocate pool of a particular type.
197 PoolType - Type of pool to allocate
199 Size - The amount of pool to allocate
201 Buffer - The address to return a pointer to the allocated pool
205 EFI_INVALID_PARAMETER - PoolType not valid
207 EFI_OUT_OF_RESOURCES - Size exceeds max pool size or allocation failed.
209 EFI_SUCCESS - Pool successfully allocated.
216 // If it's not a valid type, fail it
218 if ((PoolType
>= EfiMaxMemoryType
&& PoolType
<= 0x7fffffff) ||
219 PoolType
== EfiConventionalMemory
) {
220 return EFI_INVALID_PARAMETER
;
226 // If size is too large, fail it
227 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES
229 if (Size
> MAX_POOL_SIZE
) {
230 return EFI_OUT_OF_RESOURCES
;
234 // Acquire the memory lock and make the allocation
236 Status
= CoreAcquireLockOrFail (&gMemoryLock
);
237 if (EFI_ERROR (Status
)) {
238 return EFI_OUT_OF_RESOURCES
;
241 *Buffer
= CoreAllocatePoolI (PoolType
, Size
);
242 CoreReleaseMemoryLock ();
243 return (*Buffer
!= NULL
) ? EFI_SUCCESS
: EFI_OUT_OF_RESOURCES
;
249 IN EFI_MEMORY_TYPE PoolType
,
256 Internal function to allocate pool of a particular type.
258 Caller must have the memory lock held
263 PoolType - Type of pool to allocate
265 Size - The amount of pool to allocate
269 The allocate pool, or NULL
285 ASSERT_LOCKED (&gMemoryLock
);
288 // Adjust the size by the pool header & tail overhead
292 // Adjusting the Size to be of proper alignment so that
293 // we don't get an unaligned access fault later when
294 // pool_Tail is being initialized
296 ALIGN_VARIABLE (Size
, Adjustment
);
298 Size
+= POOL_OVERHEAD
;
299 Index
= SIZE_TO_LIST(Size
);
300 Pool
= LookupPoolHead (PoolType
);
307 // If allocation is over max size, just allocate pages for the request
310 if (Index
>= MAX_POOL_LIST
) {
311 NoPages
= EFI_SIZE_TO_PAGES(Size
) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
) - 1;
312 NoPages
&= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
) - 1);
313 Head
= CoreAllocatePoolPages (PoolType
, NoPages
, DEFAULT_PAGE_ALLOCATION
);
318 // If there's no free pool in the proper list size, go get some more pages
320 if (IsListEmpty (&Pool
->FreeList
[Index
])) {
325 NewPage
= CoreAllocatePoolPages(PoolType
, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
), DEFAULT_PAGE_ALLOCATION
);
326 if (NewPage
== NULL
) {
331 // Carve up new page into free pool blocks
334 while (offset
< DEFAULT_PAGE_ALLOCATION
) {
335 ASSERT (Index
< MAX_POOL_LIST
);
336 FSize
= LIST_TO_SIZE(Index
);
338 while (offset
+ FSize
<= DEFAULT_PAGE_ALLOCATION
) {
339 Free
= (POOL_FREE
*) &NewPage
[offset
];
340 Free
->Signature
= POOL_FREE_SIGNATURE
;
341 Free
->Index
= (UINT32
)Index
;
342 InsertHeadList (&Pool
->FreeList
[Index
], &Free
->Link
);
349 ASSERT (offset
== DEFAULT_PAGE_ALLOCATION
);
350 Index
= SIZE_TO_LIST(Size
);
354 // Remove entry from free pool list
356 Free
= CR (Pool
->FreeList
[Index
].ForwardLink
, POOL_FREE
, Link
, POOL_FREE_SIGNATURE
);
357 RemoveEntryList (&Free
->Link
);
359 Head
= (POOL_HEAD
*) Free
;
367 // If we have a pool buffer, fill in the header & tail info
369 Head
->Signature
= POOL_HEAD_SIGNATURE
;
370 Head
->Size
= (UINT32
) Size
;
371 Head
->Type
= (EFI_MEMORY_TYPE
) PoolType
;
372 Tail
= HEAD_TO_TAIL (Head
);
373 Tail
->Signature
= POOL_TAIL_SIGNATURE
;
374 Tail
->Size
= (UINT32
) Size
;
376 DEBUG_CLEAR_MEMORY (Buffer
, Size
- POOL_OVERHEAD
);
380 "AllcocatePoolI: Type %x, Addr %x (len %x) %,d\n",
383 Size
- POOL_OVERHEAD
,
388 // Account the allocation
393 DEBUG ((EFI_D_ERROR
| EFI_D_POOL
, "AllocatePool: failed to allocate %d bytes\n", Size
));
414 Buffer - The allocated pool entry to free
418 EFI_INVALID_PARAMETER - Buffer is not a valid value.
420 EFI_SUCCESS - Pool successfully freed.
426 if (NULL
== Buffer
) {
427 return EFI_INVALID_PARAMETER
;
430 CoreAcquireMemoryLock ();
431 Status
= CoreFreePoolI (Buffer
);
432 CoreReleaseMemoryLock ();
445 Internal function to free a pool entry.
447 Caller must have the memory lock held
452 Buffer - The allocated pool entry to free
456 EFI_INVALID_PARAMETER - Buffer not valid
458 EFI_SUCCESS - Buffer successfully freed.
474 ASSERT(NULL
!= Buffer
);
476 // Get the head & tail of the pool entry
478 Head
= CR (Buffer
, POOL_HEAD
, Data
, POOL_HEAD_SIGNATURE
);
479 ASSERT(NULL
!= Head
);
481 if (Head
->Signature
!= POOL_HEAD_SIGNATURE
) {
482 return EFI_INVALID_PARAMETER
;
485 Tail
= HEAD_TO_TAIL (Head
);
486 ASSERT(NULL
!= Tail
);
491 ASSERT (Tail
->Signature
== POOL_TAIL_SIGNATURE
);
492 ASSERT (Head
->Size
== Tail
->Size
);
493 ASSERT_LOCKED (&gMemoryLock
);
495 if (Tail
->Signature
!= POOL_TAIL_SIGNATURE
) {
496 return EFI_INVALID_PARAMETER
;
499 if (Head
->Size
!= Tail
->Size
) {
500 return EFI_INVALID_PARAMETER
;
504 // Determine the pool type and account for it
507 Pool
= LookupPoolHead (Head
->Type
);
509 return EFI_INVALID_PARAMETER
;
512 DEBUG ((EFI_D_POOL
, "FreePool: %x (len %x) %,d\n", Head
->Data
, Head
->Size
- POOL_OVERHEAD
, Pool
->Used
));
515 // Determine the pool list
517 Index
= SIZE_TO_LIST(Size
);
518 DEBUG_CLEAR_MEMORY (Head
, Size
);
521 // If it's not on the list, it must be pool pages
523 if (Index
>= MAX_POOL_LIST
) {
526 // Return the memory pages back to free memory
528 NoPages
= EFI_SIZE_TO_PAGES(Size
) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
) - 1;
529 NoPages
&= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
) - 1);
530 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Head
, NoPages
);
535 // Put the pool entry onto the free pool list
537 Free
= (POOL_FREE
*) Head
;
538 ASSERT(NULL
!= Free
);
539 Free
->Signature
= POOL_FREE_SIGNATURE
;
540 Free
->Index
= (UINT32
)Index
;
541 InsertHeadList (&Pool
->FreeList
[Index
], &Free
->Link
);
544 // See if all the pool entries in the same page as Free are freed pool
547 NewPage
= (CHAR8
*)((UINTN
)Free
& ~((DEFAULT_PAGE_ALLOCATION
) -1));
548 Free
= (POOL_FREE
*) &NewPage
[0];
549 ASSERT(NULL
!= Free
);
551 if (Free
->Signature
== POOL_FREE_SIGNATURE
) {
558 while ((offset
< DEFAULT_PAGE_ALLOCATION
) && (AllFree
)) {
559 FSize
= LIST_TO_SIZE(Index
);
560 while (offset
+ FSize
<= DEFAULT_PAGE_ALLOCATION
) {
561 Free
= (POOL_FREE
*) &NewPage
[offset
];
562 ASSERT(NULL
!= Free
);
563 if (Free
->Signature
!= POOL_FREE_SIGNATURE
) {
574 // All of the pool entries in the same page as Free are free pool
576 // Remove all of these pool entries from the free loop lists.
578 Free
= (POOL_FREE
*) &NewPage
[0];
579 ASSERT(NULL
!= Free
);
583 while (offset
< DEFAULT_PAGE_ALLOCATION
) {
584 FSize
= LIST_TO_SIZE(Index
);
585 while (offset
+ FSize
<= DEFAULT_PAGE_ALLOCATION
) {
586 Free
= (POOL_FREE
*) &NewPage
[offset
];
587 ASSERT(NULL
!= Free
);
588 RemoveEntryList (&Free
->Link
);
597 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS
) (UINTN
)NewPage
, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION
));
603 // If this is an OS specific memory type, then check to see if the last
604 // portion of that memory type has been freed. If it has, then free the
605 // list entry for that memory type
607 if (Pool
->MemoryType
< 0 && Pool
->Used
== 0) {
608 RemoveEntryList (&Pool
->Link
);
609 CoreFreePoolI (Pool
);