2 UEFI Memory pool management functions.
4 Copyright (c) 2006 - 2014, 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')
47 #define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))
49 #define HEAD_TO_TAIL(a) \
50 ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
53 #define SIZE_TO_LIST(a) ((a) >> POOL_SHIFT)
54 #define LIST_TO_SIZE(a) ((a+1) << POOL_SHIFT)
56 #define MAX_POOL_LIST SIZE_TO_LIST(DEFAULT_PAGE_ALLOCATION)
58 #define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)
64 #define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')
68 EFI_MEMORY_TYPE MemoryType
;
69 LIST_ENTRY FreeList
[MAX_POOL_LIST
];
74 // Pool header for each memory type.
76 POOL mPoolHead
[EfiMaxMemoryType
];
79 // List of pool header to search for the appropriate memory type.
81 LIST_ENTRY mPoolHeadList
= INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList
);
85 Called to initialize the pool.
96 for (Type
=0; Type
< EfiMaxMemoryType
; Type
++) {
97 mPoolHead
[Type
].Signature
= 0;
98 mPoolHead
[Type
].Used
= 0;
99 mPoolHead
[Type
].MemoryType
= (EFI_MEMORY_TYPE
) Type
;
100 for (Index
=0; Index
< MAX_POOL_LIST
; Index
++) {
101 InitializeListHead (&mPoolHead
[Type
].FreeList
[Index
]);
108 Look up pool head for specified memory type.
110 @param MemoryType Memory type of which pool head is looked for
112 @return Pointer of Corresponding pool head.
117 IN EFI_MEMORY_TYPE MemoryType
124 if ((UINT32
)MemoryType
< EfiMaxMemoryType
) {
125 return &mPoolHead
[MemoryType
];
129 // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI
130 // OS loaders that are provided by operating system vendors
132 if ((INT32
)MemoryType
< 0) {
134 for (Link
= mPoolHeadList
.ForwardLink
; Link
!= &mPoolHeadList
; Link
= Link
->ForwardLink
) {
135 Pool
= CR(Link
, POOL
, Link
, POOL_SIGNATURE
);
136 if (Pool
->MemoryType
== MemoryType
) {
141 Pool
= CoreAllocatePoolI (EfiBootServicesData
, sizeof (POOL
));
146 Pool
->Signature
= POOL_SIGNATURE
;
148 Pool
->MemoryType
= MemoryType
;
149 for (Index
=0; Index
< MAX_POOL_LIST
; Index
++) {
150 InitializeListHead (&Pool
->FreeList
[Index
]);
153 InsertHeadList (&mPoolHeadList
, &Pool
->Link
);
164 Allocate pool of a particular type.
166 @param PoolType Type of pool to allocate
167 @param Size The amount of pool to allocate
168 @param Buffer The address to return a pointer to the allocated
171 @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL.
172 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
173 @retval EFI_SUCCESS Pool successfully allocated.
178 CoreInternalAllocatePool (
179 IN EFI_MEMORY_TYPE PoolType
,
187 // If it's not a valid type, fail it
189 if ((PoolType
>= EfiMaxMemoryType
&& PoolType
<= 0x7fffffff) ||
190 PoolType
== EfiConventionalMemory
) {
191 return EFI_INVALID_PARAMETER
;
194 if (Buffer
== NULL
) {
195 return EFI_INVALID_PARAMETER
;
201 // If size is too large, fail it
202 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES
204 if (Size
> MAX_POOL_SIZE
) {
205 return EFI_OUT_OF_RESOURCES
;
209 // Acquire the memory lock and make the allocation
211 Status
= CoreAcquireLockOrFail (&gMemoryLock
);
212 if (EFI_ERROR (Status
)) {
213 return EFI_OUT_OF_RESOURCES
;
216 *Buffer
= CoreAllocatePoolI (PoolType
, Size
);
217 CoreReleaseMemoryLock ();
218 return (*Buffer
!= NULL
) ? EFI_SUCCESS
: EFI_OUT_OF_RESOURCES
;
222 Allocate pool of a particular type.
224 @param PoolType Type of pool to allocate
225 @param Size The amount of pool to allocate
226 @param Buffer The address to return a pointer to the allocated
229 @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL.
230 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
231 @retval EFI_SUCCESS Pool successfully allocated.
237 IN EFI_MEMORY_TYPE PoolType
,
244 Status
= CoreInternalAllocatePool (PoolType
, Size
, Buffer
);
245 if (!EFI_ERROR (Status
)) {
246 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0), MemoryProfileActionAllocatePool
, PoolType
, Size
, *Buffer
);
252 Internal function to allocate pool of a particular type.
253 Caller must have the memory lock held
255 @param PoolType Type of pool to allocate
256 @param Size The amount of pool to allocate
258 @return The allocate pool, or NULL
263 IN EFI_MEMORY_TYPE PoolType
,
279 ASSERT_LOCKED (&gMemoryLock
);
281 if (PoolType
== EfiACPIReclaimMemory
||
282 PoolType
== EfiACPIMemoryNVS
||
283 PoolType
== EfiRuntimeServicesCode
||
284 PoolType
== EfiRuntimeServicesData
) {
286 Granularity
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
288 Granularity
= DEFAULT_PAGE_ALLOCATION
;
292 // Adjust the size by the pool header & tail overhead
296 // Adjusting the Size to be of proper alignment so that
297 // we don't get an unaligned access fault later when
298 // pool_Tail is being initialized
300 Size
= ALIGN_VARIABLE (Size
);
302 Size
+= POOL_OVERHEAD
;
303 Index
= SIZE_TO_LIST(Size
);
304 Pool
= LookupPoolHead (PoolType
);
311 // If allocation is over max size, just allocate pages for the request
314 if (Index
>= MAX_POOL_LIST
) {
315 NoPages
= EFI_SIZE_TO_PAGES(Size
) + EFI_SIZE_TO_PAGES (Granularity
) - 1;
316 NoPages
&= ~(UINTN
)(EFI_SIZE_TO_PAGES (Granularity
) - 1);
317 Head
= CoreAllocatePoolPages (PoolType
, NoPages
, Granularity
);
322 // If there's no free pool in the proper list size, go get some more pages
324 if (IsListEmpty (&Pool
->FreeList
[Index
])) {
329 NewPage
= CoreAllocatePoolPages(PoolType
, EFI_SIZE_TO_PAGES (Granularity
), Granularity
);
330 if (NewPage
== NULL
) {
335 // Carve up new page into free pool blocks
338 while (Offset
< Granularity
) {
339 ASSERT (Index
< MAX_POOL_LIST
);
340 FSize
= LIST_TO_SIZE(Index
);
342 while (Offset
+ FSize
<= Granularity
) {
343 Free
= (POOL_FREE
*) &NewPage
[Offset
];
344 Free
->Signature
= POOL_FREE_SIGNATURE
;
345 Free
->Index
= (UINT32
)Index
;
346 InsertHeadList (&Pool
->FreeList
[Index
], &Free
->Link
);
353 ASSERT (Offset
== Granularity
);
354 Index
= SIZE_TO_LIST(Size
);
358 // Remove entry from free pool list
360 Free
= CR (Pool
->FreeList
[Index
].ForwardLink
, POOL_FREE
, Link
, POOL_FREE_SIGNATURE
);
361 RemoveEntryList (&Free
->Link
);
363 Head
= (POOL_HEAD
*) Free
;
371 // If we have a pool buffer, fill in the header & tail info
373 Head
->Signature
= POOL_HEAD_SIGNATURE
;
375 Head
->Type
= (EFI_MEMORY_TYPE
) PoolType
;
376 Tail
= HEAD_TO_TAIL (Head
);
377 Tail
->Signature
= POOL_TAIL_SIGNATURE
;
380 DEBUG_CLEAR_MEMORY (Buffer
, Size
- POOL_OVERHEAD
);
384 "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType
,
386 (UINT64
)(Size
- POOL_OVERHEAD
),
391 // Account the allocation
396 DEBUG ((DEBUG_ERROR
| DEBUG_POOL
, "AllocatePool: failed to allocate %ld bytes\n", (UINT64
) Size
));
407 @param Buffer The allocated pool entry to free
409 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
410 @retval EFI_SUCCESS Pool successfully freed.
415 CoreInternalFreePool (
421 if (Buffer
== NULL
) {
422 return EFI_INVALID_PARAMETER
;
425 CoreAcquireMemoryLock ();
426 Status
= CoreFreePoolI (Buffer
);
427 CoreReleaseMemoryLock ();
434 @param Buffer The allocated pool entry to free
436 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
437 @retval EFI_SUCCESS Pool successfully freed.
448 Status
= CoreInternalFreePool (Buffer
);
449 if (!EFI_ERROR (Status
)) {
450 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0), MemoryProfileActionFreePool
, (EFI_MEMORY_TYPE
) 0, 0, Buffer
);
456 Internal function to free a pool entry.
457 Caller must have the memory lock held
459 @param Buffer The allocated pool entry to free
461 @retval EFI_INVALID_PARAMETER Buffer not valid
462 @retval EFI_SUCCESS Buffer successfully freed.
483 ASSERT(Buffer
!= NULL
);
485 // Get the head & tail of the pool entry
487 Head
= CR (Buffer
, POOL_HEAD
, Data
, POOL_HEAD_SIGNATURE
);
488 ASSERT(Head
!= NULL
);
490 if (Head
->Signature
!= POOL_HEAD_SIGNATURE
) {
491 return EFI_INVALID_PARAMETER
;
494 Tail
= HEAD_TO_TAIL (Head
);
495 ASSERT(Tail
!= NULL
);
500 ASSERT (Tail
->Signature
== POOL_TAIL_SIGNATURE
);
501 ASSERT (Head
->Size
== Tail
->Size
);
502 ASSERT_LOCKED (&gMemoryLock
);
504 if (Tail
->Signature
!= POOL_TAIL_SIGNATURE
) {
505 return EFI_INVALID_PARAMETER
;
508 if (Head
->Size
!= Tail
->Size
) {
509 return EFI_INVALID_PARAMETER
;
513 // Determine the pool type and account for it
516 Pool
= LookupPoolHead (Head
->Type
);
518 return EFI_INVALID_PARAMETER
;
521 DEBUG ((DEBUG_POOL
, "FreePool: %p (len %lx) %,ld\n", Head
->Data
, (UINT64
)(Head
->Size
- POOL_OVERHEAD
), (UINT64
) Pool
->Used
));
523 if (Head
->Type
== EfiACPIReclaimMemory
||
524 Head
->Type
== EfiACPIMemoryNVS
||
525 Head
->Type
== EfiRuntimeServicesCode
||
526 Head
->Type
== EfiRuntimeServicesData
) {
528 Granularity
= EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT
;
530 Granularity
= DEFAULT_PAGE_ALLOCATION
;
534 // Determine the pool list
536 Index
= SIZE_TO_LIST(Size
);
537 DEBUG_CLEAR_MEMORY (Head
, Size
);
540 // If it's not on the list, it must be pool pages
542 if (Index
>= MAX_POOL_LIST
) {
545 // Return the memory pages back to free memory
547 NoPages
= EFI_SIZE_TO_PAGES(Size
) + EFI_SIZE_TO_PAGES (Granularity
) - 1;
548 NoPages
&= ~(UINTN
)(EFI_SIZE_TO_PAGES (Granularity
) - 1);
549 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Head
, NoPages
);
554 // Put the pool entry onto the free pool list
556 Free
= (POOL_FREE
*) Head
;
557 ASSERT(Free
!= NULL
);
558 Free
->Signature
= POOL_FREE_SIGNATURE
;
559 Free
->Index
= (UINT32
)Index
;
560 InsertHeadList (&Pool
->FreeList
[Index
], &Free
->Link
);
563 // See if all the pool entries in the same page as Free are freed pool
566 NewPage
= (CHAR8
*)((UINTN
)Free
& ~(Granularity
- 1));
567 Free
= (POOL_FREE
*) &NewPage
[0];
568 ASSERT(Free
!= NULL
);
570 if (Free
->Signature
== POOL_FREE_SIGNATURE
) {
577 while ((Offset
< Granularity
) && (AllFree
)) {
578 FSize
= LIST_TO_SIZE(Index
);
579 while (Offset
+ FSize
<= Granularity
) {
580 Free
= (POOL_FREE
*) &NewPage
[Offset
];
581 ASSERT(Free
!= NULL
);
582 if (Free
->Signature
!= POOL_FREE_SIGNATURE
) {
593 // All of the pool entries in the same page as Free are free pool
595 // Remove all of these pool entries from the free loop lists.
597 Free
= (POOL_FREE
*) &NewPage
[0];
598 ASSERT(Free
!= NULL
);
602 while (Offset
< Granularity
) {
603 FSize
= LIST_TO_SIZE(Index
);
604 while (Offset
+ FSize
<= Granularity
) {
605 Free
= (POOL_FREE
*) &NewPage
[Offset
];
606 ASSERT(Free
!= NULL
);
607 RemoveEntryList (&Free
->Link
);
616 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS
) (UINTN
)NewPage
, EFI_SIZE_TO_PAGES (Granularity
));
622 // If this is an OS specific memory type, then check to see if the last
623 // portion of that memory type has been freed. If it has, then free the
624 // list entry for that memory type
626 if ((INT32
)Pool
->MemoryType
< 0 && Pool
->Used
== 0) {
627 RemoveEntryList (&Pool
->Link
);
628 CoreFreePoolI (Pool
);