2 UEFI Memory pool management functions.
4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5 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.
18 #define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0')
26 #define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')
35 #define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)
37 #define POOL_TAIL_SIGNATURE SIGNATURE_32('p','t','a','l')
44 #define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))
46 #define HEAD_TO_TAIL(a) \
47 ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
50 // Each element is the sum of the 2 previous ones: this allows us to migrate
51 // blocks between bins by splitting them up, while not wasting too much memory
52 // as we would in a strict power-of-2 sequence
54 STATIC CONST UINT16 mPoolSizeTable
[] = {
55 64, 128, 192, 320, 512, 832, 1344, 2176, 3520, 5696, 9216, 14912, 24128
58 #define SIZE_TO_LIST(a) (GetPoolIndexFromSize (a))
59 #define LIST_TO_SIZE(a) (mPoolSizeTable [a])
61 #define MAX_POOL_LIST (sizeof (mPoolSizeTable) / sizeof (mPoolSizeTable[0]))
63 #define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)
69 #define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')
73 EFI_MEMORY_TYPE MemoryType
;
74 LIST_ENTRY FreeList
[MAX_POOL_LIST
];
79 // Pool header for each memory type.
81 POOL mPoolHead
[EfiMaxMemoryType
];
84 // List of pool header to search for the appropriate memory type.
86 LIST_ENTRY mPoolHeadList
= INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList
);
89 Get pool size table index from the specified size.
91 @param Size The specified size to get index from pool table.
93 @return The index of pool size table.
98 GetPoolIndexFromSize (
104 for (Index
= 0; Index
< MAX_POOL_LIST
; Index
++) {
105 if (mPoolSizeTable
[Index
] >= Size
) {
109 return MAX_POOL_LIST
;
113 Called to initialize the pool.
124 for (Type
=0; Type
< EfiMaxMemoryType
; Type
++) {
125 mPoolHead
[Type
].Signature
= 0;
126 mPoolHead
[Type
].Used
= 0;
127 mPoolHead
[Type
].MemoryType
= (EFI_MEMORY_TYPE
) Type
;
128 for (Index
=0; Index
< MAX_POOL_LIST
; Index
++) {
129 InitializeListHead (&mPoolHead
[Type
].FreeList
[Index
]);
136 Look up pool head for specified memory type.
138 @param MemoryType Memory type of which pool head is looked for
140 @return Pointer of Corresponding pool head.
145 IN EFI_MEMORY_TYPE MemoryType
152 if ((UINT32
)MemoryType
< EfiMaxMemoryType
) {
153 return &mPoolHead
[MemoryType
];
157 // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI
158 // OS loaders that are provided by operating system vendors.
159 // MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.
161 if ((UINT32
) MemoryType
>= MEMORY_TYPE_OEM_RESERVED_MIN
) {
163 for (Link
= mPoolHeadList
.ForwardLink
; Link
!= &mPoolHeadList
; Link
= Link
->ForwardLink
) {
164 Pool
= CR(Link
, POOL
, Link
, POOL_SIGNATURE
);
165 if (Pool
->MemoryType
== MemoryType
) {
170 Pool
= CoreAllocatePoolI (EfiBootServicesData
, sizeof (POOL
));
175 Pool
->Signature
= POOL_SIGNATURE
;
177 Pool
->MemoryType
= MemoryType
;
178 for (Index
=0; Index
< MAX_POOL_LIST
; Index
++) {
179 InitializeListHead (&Pool
->FreeList
[Index
]);
182 InsertHeadList (&mPoolHeadList
, &Pool
->Link
);
193 Allocate pool of a particular type.
195 @param PoolType Type of pool to allocate
196 @param Size The amount of pool to allocate
197 @param Buffer The address to return a pointer to the allocated
200 @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL.
201 PoolType was EfiPersistentMemory.
202 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
203 @retval EFI_SUCCESS Pool successfully allocated.
208 CoreInternalAllocatePool (
209 IN EFI_MEMORY_TYPE PoolType
,
217 // If it's not a valid type, fail it
219 if ((PoolType
>= EfiMaxMemoryType
&& PoolType
< MEMORY_TYPE_OEM_RESERVED_MIN
) ||
220 (PoolType
== EfiConventionalMemory
) || (PoolType
== EfiPersistentMemory
)) {
221 return EFI_INVALID_PARAMETER
;
224 if (Buffer
== NULL
) {
225 return EFI_INVALID_PARAMETER
;
231 // If size is too large, fail it
232 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES
234 if (Size
> MAX_POOL_SIZE
) {
235 return EFI_OUT_OF_RESOURCES
;
239 // Acquire the memory lock and make the allocation
241 Status
= CoreAcquireLockOrFail (&gMemoryLock
);
242 if (EFI_ERROR (Status
)) {
243 return EFI_OUT_OF_RESOURCES
;
246 *Buffer
= CoreAllocatePoolI (PoolType
, Size
);
247 CoreReleaseMemoryLock ();
248 return (*Buffer
!= NULL
) ? EFI_SUCCESS
: EFI_OUT_OF_RESOURCES
;
252 Allocate pool of a particular type.
254 @param PoolType Type of pool to allocate
255 @param Size The amount of pool to allocate
256 @param Buffer The address to return a pointer to the allocated
259 @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL.
260 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
261 @retval EFI_SUCCESS Pool successfully allocated.
267 IN EFI_MEMORY_TYPE PoolType
,
274 Status
= CoreInternalAllocatePool (PoolType
, Size
, Buffer
);
275 if (!EFI_ERROR (Status
)) {
276 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0), MemoryProfileActionAllocatePool
, PoolType
, Size
, *Buffer
);
282 Internal function to allocate pool of a particular type.
283 Caller must have the memory lock held
285 @param PoolType Type of pool to allocate
286 @param Size The amount of pool to allocate
288 @return The allocate pool, or NULL
293 IN EFI_MEMORY_TYPE PoolType
,
305 UINTN Offset
, MaxOffset
;
309 ASSERT_LOCKED (&gMemoryLock
);
311 if (PoolType
== EfiACPIReclaimMemory
||
312 PoolType
== EfiACPIMemoryNVS
||
313 PoolType
== EfiRuntimeServicesCode
||
314 PoolType
== EfiRuntimeServicesData
) {
316 Granularity
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
318 Granularity
= DEFAULT_PAGE_ALLOCATION
;
322 // Adjust the size by the pool header & tail overhead
326 // Adjusting the Size to be of proper alignment so that
327 // we don't get an unaligned access fault later when
328 // pool_Tail is being initialized
330 Size
= ALIGN_VARIABLE (Size
);
332 Size
+= POOL_OVERHEAD
;
333 Index
= SIZE_TO_LIST(Size
);
334 Pool
= LookupPoolHead (PoolType
);
341 // If allocation is over max size, just allocate pages for the request
344 if (Index
>= SIZE_TO_LIST (Granularity
)) {
345 NoPages
= EFI_SIZE_TO_PAGES(Size
) + EFI_SIZE_TO_PAGES (Granularity
) - 1;
346 NoPages
&= ~(UINTN
)(EFI_SIZE_TO_PAGES (Granularity
) - 1);
347 Head
= CoreAllocatePoolPages (PoolType
, NoPages
, Granularity
);
352 // If there's no free pool in the proper list size, go get some more pages
354 if (IsListEmpty (&Pool
->FreeList
[Index
])) {
356 Offset
= LIST_TO_SIZE (Index
);
357 MaxOffset
= Granularity
;
360 // Check the bins holding larger blocks, and carve one up if needed
362 while (++Index
< SIZE_TO_LIST (Granularity
)) {
363 if (!IsListEmpty (&Pool
->FreeList
[Index
])) {
364 Free
= CR (Pool
->FreeList
[Index
].ForwardLink
, POOL_FREE
, Link
, POOL_FREE_SIGNATURE
);
365 RemoveEntryList (&Free
->Link
);
366 NewPage
= (VOID
*) Free
;
367 MaxOffset
= LIST_TO_SIZE (Index
);
375 NewPage
= CoreAllocatePoolPages(PoolType
, EFI_SIZE_TO_PAGES (Granularity
), Granularity
);
376 if (NewPage
== NULL
) {
381 // Serve the allocation request from the head of the allocated block
384 Head
= (POOL_HEAD
*) NewPage
;
387 // Carve up remaining space into free pool blocks
390 while (Offset
< MaxOffset
) {
391 ASSERT (Index
< MAX_POOL_LIST
);
392 FSize
= LIST_TO_SIZE(Index
);
394 while (Offset
+ FSize
<= MaxOffset
) {
395 Free
= (POOL_FREE
*) &NewPage
[Offset
];
396 Free
->Signature
= POOL_FREE_SIGNATURE
;
397 Free
->Index
= (UINT32
)Index
;
398 InsertHeadList (&Pool
->FreeList
[Index
], &Free
->Link
);
404 ASSERT (Offset
== MaxOffset
);
409 // Remove entry from free pool list
411 Free
= CR (Pool
->FreeList
[Index
].ForwardLink
, POOL_FREE
, Link
, POOL_FREE_SIGNATURE
);
412 RemoveEntryList (&Free
->Link
);
414 Head
= (POOL_HEAD
*) Free
;
422 // If we have a pool buffer, fill in the header & tail info
424 Head
->Signature
= POOL_HEAD_SIGNATURE
;
426 Head
->Type
= (EFI_MEMORY_TYPE
) PoolType
;
427 Tail
= HEAD_TO_TAIL (Head
);
428 Tail
->Signature
= POOL_TAIL_SIGNATURE
;
431 DEBUG_CLEAR_MEMORY (Buffer
, Size
- POOL_OVERHEAD
);
435 "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType
,
437 (UINT64
)(Size
- POOL_OVERHEAD
),
442 // Account the allocation
447 DEBUG ((DEBUG_ERROR
| DEBUG_POOL
, "AllocatePool: failed to allocate %ld bytes\n", (UINT64
) Size
));
458 @param Buffer The allocated pool entry to free
460 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
461 @retval EFI_SUCCESS Pool successfully freed.
466 CoreInternalFreePool (
472 if (Buffer
== NULL
) {
473 return EFI_INVALID_PARAMETER
;
476 CoreAcquireMemoryLock ();
477 Status
= CoreFreePoolI (Buffer
);
478 CoreReleaseMemoryLock ();
485 @param Buffer The allocated pool entry to free
487 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
488 @retval EFI_SUCCESS Pool successfully freed.
499 Status
= CoreInternalFreePool (Buffer
);
500 if (!EFI_ERROR (Status
)) {
501 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0), MemoryProfileActionFreePool
, (EFI_MEMORY_TYPE
) 0, 0, Buffer
);
507 Internal function to free a pool entry.
508 Caller must have the memory lock held
510 @param Buffer The allocated pool entry to free
512 @retval EFI_INVALID_PARAMETER Buffer not valid
513 @retval EFI_SUCCESS Buffer successfully freed.
533 ASSERT(Buffer
!= NULL
);
535 // Get the head & tail of the pool entry
537 Head
= CR (Buffer
, POOL_HEAD
, Data
, POOL_HEAD_SIGNATURE
);
538 ASSERT(Head
!= NULL
);
540 if (Head
->Signature
!= POOL_HEAD_SIGNATURE
) {
541 return EFI_INVALID_PARAMETER
;
544 Tail
= HEAD_TO_TAIL (Head
);
545 ASSERT(Tail
!= NULL
);
550 ASSERT (Tail
->Signature
== POOL_TAIL_SIGNATURE
);
551 ASSERT (Head
->Size
== Tail
->Size
);
552 ASSERT_LOCKED (&gMemoryLock
);
554 if (Tail
->Signature
!= POOL_TAIL_SIGNATURE
) {
555 return EFI_INVALID_PARAMETER
;
558 if (Head
->Size
!= Tail
->Size
) {
559 return EFI_INVALID_PARAMETER
;
563 // Determine the pool type and account for it
566 Pool
= LookupPoolHead (Head
->Type
);
568 return EFI_INVALID_PARAMETER
;
571 DEBUG ((DEBUG_POOL
, "FreePool: %p (len %lx) %,ld\n", Head
->Data
, (UINT64
)(Head
->Size
- POOL_OVERHEAD
), (UINT64
) Pool
->Used
));
573 if (Head
->Type
== EfiACPIReclaimMemory
||
574 Head
->Type
== EfiACPIMemoryNVS
||
575 Head
->Type
== EfiRuntimeServicesCode
||
576 Head
->Type
== EfiRuntimeServicesData
) {
578 Granularity
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
580 Granularity
= DEFAULT_PAGE_ALLOCATION
;
584 // Determine the pool list
586 Index
= SIZE_TO_LIST(Size
);
587 DEBUG_CLEAR_MEMORY (Head
, Size
);
590 // If it's not on the list, it must be pool pages
592 if (Index
>= SIZE_TO_LIST (Granularity
)) {
595 // Return the memory pages back to free memory
597 NoPages
= EFI_SIZE_TO_PAGES(Size
) + EFI_SIZE_TO_PAGES (Granularity
) - 1;
598 NoPages
&= ~(UINTN
)(EFI_SIZE_TO_PAGES (Granularity
) - 1);
599 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Head
, NoPages
);
604 // Put the pool entry onto the free pool list
606 Free
= (POOL_FREE
*) Head
;
607 ASSERT(Free
!= NULL
);
608 Free
->Signature
= POOL_FREE_SIGNATURE
;
609 Free
->Index
= (UINT32
)Index
;
610 InsertHeadList (&Pool
->FreeList
[Index
], &Free
->Link
);
613 // See if all the pool entries in the same page as Free are freed pool
616 NewPage
= (CHAR8
*)((UINTN
)Free
& ~(Granularity
- 1));
617 Free
= (POOL_FREE
*) &NewPage
[0];
618 ASSERT(Free
!= NULL
);
620 if (Free
->Signature
== POOL_FREE_SIGNATURE
) {
625 while ((Offset
< Granularity
) && (AllFree
)) {
626 Free
= (POOL_FREE
*) &NewPage
[Offset
];
627 ASSERT(Free
!= NULL
);
628 if (Free
->Signature
!= POOL_FREE_SIGNATURE
) {
631 Offset
+= LIST_TO_SIZE(Free
->Index
);
637 // All of the pool entries in the same page as Free are free pool
639 // Remove all of these pool entries from the free loop lists.
641 Free
= (POOL_FREE
*) &NewPage
[0];
642 ASSERT(Free
!= NULL
);
645 while (Offset
< Granularity
) {
646 Free
= (POOL_FREE
*) &NewPage
[Offset
];
647 ASSERT(Free
!= NULL
);
648 RemoveEntryList (&Free
->Link
);
649 Offset
+= LIST_TO_SIZE(Free
->Index
);
655 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS
) (UINTN
)NewPage
, EFI_SIZE_TO_PAGES (Granularity
));
661 // If this is an OS specific memory type, then check to see if the last
662 // portion of that memory type has been freed. If it has, then free the
663 // list entry for that memory type
665 if ((INT32
)Pool
->MemoryType
< 0 && Pool
->Used
== 0) {
666 RemoveEntryList (&Pool
->Link
);
667 CoreFreePoolI (Pool
);