2 UncachedMemoryAllocation lib that uses DXE Service to change cachability for
5 Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
6 Copyright (c) 2014, AMR Ltd. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #include <Library/BaseLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/DebugLib.h>
23 #include <Library/UefiBootServicesTableLib.h>
24 #include <Library/UncachedMemoryAllocationLib.h>
25 #include <Library/PcdLib.h>
26 #include <Library/ArmLib.h>
27 #include <Library/DxeServicesTableLib.h>
28 #include <Library/CacheMaintenanceLib.h>
31 UncachedInternalAllocatePages (
32 IN EFI_MEMORY_TYPE MemoryType
,
37 UncachedInternalAllocateAlignedPages (
38 IN EFI_MEMORY_TYPE MemoryType
,
46 // Assume all of memory has the same cache attributes, unless we do our magic
51 EFI_PHYSICAL_ADDRESS Base
;
54 EFI_MEMORY_TYPE MemoryType
;
59 STATIC LIST_ENTRY mPageList
= INITIALIZE_LIST_HEAD_VARIABLE (mPageList
);
60 // Track the size of the non-allocated buffer in the linked-list
61 STATIC UINTN mFreedBufferSize
= 0;
64 * This function firstly checks if the requested allocation can fit into one
65 * of the previously allocated buffer.
66 * If the requested allocation does not fit in the existing pool then
67 * the function makes a new allocation.
69 * @param MemoryType Type of memory requested for the new allocation
70 * @param Pages Number of requested page
71 * @param Alignment Required alignment
72 * @param Allocation Address of the newly allocated buffer
74 * @return EFI_SUCCESS If the function manage to allocate a buffer
75 * @return !EFI_SUCCESS If the function did not manage to allocate a buffer
79 AllocatePagesFromList (
80 IN EFI_MEMORY_TYPE MemoryType
,
89 FREE_PAGE_NODE
*NewNode
;
91 EFI_PHYSICAL_ADDRESS Memory
;
92 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
94 // Alignment must be a power of two or zero.
95 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
98 // Look in our list for the smallest page that could satisfy the new allocation
102 for (Link
= mPageList
.ForwardLink
; Link
!= &mPageList
; Link
= Link
->ForwardLink
) {
103 Node
= BASE_CR (Link
, FREE_PAGE_NODE
, Link
);
104 if ((Node
->Allocated
== FALSE
) && (Node
->MemoryType
== MemoryType
)) {
105 // We have a node that fits our requirements
106 if (((UINTN
)Node
->Base
& (Alignment
- 1)) == 0) {
107 // We found a page that matches the page size
108 if (Node
->Pages
== Pages
) {
109 Node
->Allocated
= TRUE
;
110 Node
->Allocation
= (VOID
*)(UINTN
)Node
->Base
;
111 *Allocation
= Node
->Allocation
;
113 // Update the size of the freed buffer
114 mFreedBufferSize
-= Pages
* EFI_PAGE_SIZE
;
116 } else if (Node
->Pages
> Pages
) {
117 if (NewNode
== NULL
) {
118 // It is the first node that could contain our new allocation
120 } else if (NewNode
->Pages
> Node
->Pages
) {
121 // This node offers a smaller number of page.
128 // Check if we have found a node that could contain our new allocation
129 if (NewNode
!= NULL
) {
130 NewNode
->Allocated
= TRUE
;
131 NewNode
->Allocation
= (VOID
*)(UINTN
)NewNode
->Base
;
132 *Allocation
= NewNode
->Allocation
;
133 mFreedBufferSize
-= NewNode
->Pages
* EFI_PAGE_SIZE
;
138 // Otherwise, we need to allocate a new buffer
141 // We do not want to over-allocate in case the alignment requirement does not
142 // require extra pages
143 if (Alignment
> EFI_PAGE_SIZE
) {
144 AlignmentMask
= Alignment
- 1;
145 Pages
+= EFI_SIZE_TO_PAGES (Alignment
);
150 Status
= gBS
->AllocatePages (AllocateAnyPages
, MemoryType
, Pages
, &Memory
);
151 if (EFI_ERROR (Status
)) {
155 Status
= gDS
->GetMemorySpaceDescriptor (Memory
, &Descriptor
);
156 if (!EFI_ERROR (Status
)) {
157 // We are making an assumption that all of memory has the same default attributes
158 gAttributes
= Descriptor
.Attributes
;
160 gBS
->FreePages (Memory
, Pages
);
164 Status
= gDS
->SetMemorySpaceAttributes (Memory
, EFI_PAGES_TO_SIZE (Pages
), EFI_MEMORY_WC
);
165 if (EFI_ERROR (Status
)) {
166 gBS
->FreePages (Memory
, Pages
);
170 InvalidateDataCacheRange ((VOID
*)(UINTN
)Memory
, EFI_PAGES_TO_SIZE (Pages
));
172 NewNode
= AllocatePool (sizeof (FREE_PAGE_NODE
));
173 if (NewNode
== NULL
) {
175 gBS
->FreePages (Memory
, Pages
);
176 return EFI_OUT_OF_RESOURCES
;
179 NewNode
->Base
= Memory
;
180 NewNode
->Allocation
= (VOID
*)(((UINTN
)Memory
+ AlignmentMask
) & ~AlignmentMask
);
181 NewNode
->Pages
= Pages
;
182 NewNode
->Allocated
= TRUE
;
183 NewNode
->MemoryType
= MemoryType
;
185 InsertTailList (&mPageList
, &NewNode
->Link
);
187 *Allocation
= NewNode
->Allocation
;
192 * Free the memory allocation
194 * This function will actually try to find the allocation in the linked list.
195 * And it will then mark the entry as freed.
197 * @param Allocation Base address of the buffer to free
199 * @return EFI_SUCCESS The allocation has been freed
200 * @return EFI_NOT_FOUND The allocation was not found in the pool.
201 * @return EFI_INVALID_PARAMETER If Allocation is NULL
211 FREE_PAGE_NODE
*Node
;
213 if (Allocation
== NULL
) {
214 return EFI_INVALID_PARAMETER
;
217 for (Link
= mPageList
.ForwardLink
; Link
!= &mPageList
; Link
= Link
->ForwardLink
) {
218 Node
= BASE_CR (Link
, FREE_PAGE_NODE
, Link
);
219 if ((UINTN
)Node
->Allocation
== (UINTN
)Allocation
) {
220 Node
->Allocated
= FALSE
;
222 // Update the size of the freed buffer
223 mFreedBufferSize
+= Node
->Pages
* EFI_PAGE_SIZE
;
225 // If the size of the non-allocated reaches the threshold we raise a warning.
226 // It might be an expected behaviour in some cases.
227 // We might device to free some of these buffers later on.
228 if (mFreedBufferSize
> PcdGet64 (PcdArmFreeUncachedMemorySizeThreshold
)) {
229 DEBUG ((EFI_D_WARN
, "Warning: The list of non-allocated buffer has reach the threshold.\n"));
235 return EFI_NOT_FOUND
;
239 * This function is automatically invoked when the driver exits
240 * It frees all the non-allocated memory buffer.
241 * This function is not responsible to free allocated buffer (eg: case of memory leak,
242 * runtime allocation).
246 UncachedMemoryAllocationLibDestructor (
247 IN EFI_HANDLE ImageHandle
,
248 IN EFI_SYSTEM_TABLE
*SystemTable
252 FREE_PAGE_NODE
*OldNode
;
254 // Test if the list is empty
255 Link
= mPageList
.ForwardLink
;
256 if (Link
== &mPageList
) {
260 // Free all the pages and nodes
262 OldNode
= BASE_CR (Link
, FREE_PAGE_NODE
, Link
);
263 // Point to the next entry
264 Link
= Link
->ForwardLink
;
266 // We only free the non-allocated buffer
267 if (OldNode
->Allocated
== FALSE
) {
268 gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
)(UINTN
)OldNode
->Base
, OldNode
->Pages
);
269 RemoveEntryList (&OldNode
->Link
);
272 } while (Link
!= &mPageList
);
278 Converts a cached or uncached address to a physical address suitable for use in SoC registers.
280 @param VirtualAddress The pointer to convert.
282 @return The physical address of the supplied virtual pointer.
286 ConvertToPhysicalAddress (
287 IN VOID
*VirtualAddress
290 return (EFI_PHYSICAL_ADDRESS
)(UINTN
)VirtualAddress
;
295 UncachedInternalAllocatePages (
296 IN EFI_MEMORY_TYPE MemoryType
,
300 return UncachedInternalAllocateAlignedPages (MemoryType
, Pages
, EFI_PAGE_SIZE
);
306 UncachedAllocatePages (
310 return UncachedInternalAllocatePages (EfiBootServicesData
, Pages
);
315 UncachedAllocateRuntimePages (
319 return UncachedInternalAllocatePages (EfiRuntimeServicesData
, Pages
);
324 UncachedAllocateReservedPages (
328 return UncachedInternalAllocatePages (EfiReservedMemoryType
, Pages
);
340 UncachedFreeAlignedPages (Buffer
, Pages
);
346 UncachedInternalAllocateAlignedPages (
347 IN EFI_MEMORY_TYPE MemoryType
,
360 Status
= AllocatePagesFromList (MemoryType
, Pages
, Alignment
, &Allocation
);
361 if (EFI_ERROR (Status
)) {
362 ASSERT_EFI_ERROR (Status
);
372 UncachedFreeAlignedPages (
377 FreePagesFromList (Buffer
);
382 UncachedInternalAllocateAlignedPool (
383 IN EFI_MEMORY_TYPE PoolType
,
384 IN UINTN AllocationSize
,
388 VOID
*AlignedAddress
;
391 // Alignment must be a power of two or zero.
393 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
395 if (Alignment
< EFI_PAGE_SIZE
) {
396 Alignment
= EFI_PAGE_SIZE
;
399 AlignedAddress
= UncachedInternalAllocateAlignedPages (PoolType
, EFI_SIZE_TO_PAGES (AllocationSize
), Alignment
);
400 if (AlignedAddress
== NULL
) {
404 return (VOID
*) AlignedAddress
;
409 UncachedAllocateAlignedPool (
410 IN UINTN AllocationSize
,
414 return UncachedInternalAllocateAlignedPool (EfiBootServicesData
, AllocationSize
, Alignment
);
419 UncachedAllocateAlignedRuntimePool (
420 IN UINTN AllocationSize
,
424 return UncachedInternalAllocateAlignedPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
429 UncachedAllocateAlignedReservedPool (
430 IN UINTN AllocationSize
,
434 return UncachedInternalAllocateAlignedPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
438 UncachedInternalAllocateAlignedZeroPool (
439 IN EFI_MEMORY_TYPE PoolType
,
440 IN UINTN AllocationSize
,
445 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
446 if (Memory
!= NULL
) {
447 Memory
= ZeroMem (Memory
, AllocationSize
);
454 UncachedAllocateAlignedZeroPool (
455 IN UINTN AllocationSize
,
459 return UncachedInternalAllocateAlignedZeroPool (EfiBootServicesData
, AllocationSize
, Alignment
);
464 UncachedAllocateAlignedRuntimeZeroPool (
465 IN UINTN AllocationSize
,
469 return UncachedInternalAllocateAlignedZeroPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
474 UncachedAllocateAlignedReservedZeroPool (
475 IN UINTN AllocationSize
,
479 return UncachedInternalAllocateAlignedZeroPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
483 UncachedInternalAllocateAlignedCopyPool (
484 IN EFI_MEMORY_TYPE PoolType
,
485 IN UINTN AllocationSize
,
486 IN CONST VOID
*Buffer
,
492 ASSERT (Buffer
!= NULL
);
493 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
495 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
496 if (Memory
!= NULL
) {
497 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
504 UncachedAllocateAlignedCopyPool (
505 IN UINTN AllocationSize
,
506 IN CONST VOID
*Buffer
,
510 return UncachedInternalAllocateAlignedCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
, Alignment
);
515 UncachedAllocateAlignedRuntimeCopyPool (
516 IN UINTN AllocationSize
,
517 IN CONST VOID
*Buffer
,
521 return UncachedInternalAllocateAlignedCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
, Alignment
);
526 UncachedAllocateAlignedReservedCopyPool (
527 IN UINTN AllocationSize
,
528 IN CONST VOID
*Buffer
,
532 return UncachedInternalAllocateAlignedCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
, Alignment
);
537 UncachedFreeAlignedPool (
541 UncachedFreePages (Allocation
, 0);
545 UncachedInternalAllocatePool (
546 IN EFI_MEMORY_TYPE MemoryType
,
547 IN UINTN AllocationSize
550 UINTN CacheLineLength
= ArmDataCacheLineLength ();
551 return UncachedInternalAllocateAlignedPool (MemoryType
, AllocationSize
, CacheLineLength
);
556 UncachedAllocatePool (
557 IN UINTN AllocationSize
560 return UncachedInternalAllocatePool (EfiBootServicesData
, AllocationSize
);
565 UncachedAllocateRuntimePool (
566 IN UINTN AllocationSize
569 return UncachedInternalAllocatePool (EfiRuntimeServicesData
, AllocationSize
);
574 UncachedAllocateReservedPool (
575 IN UINTN AllocationSize
578 return UncachedInternalAllocatePool (EfiReservedMemoryType
, AllocationSize
);
582 UncachedInternalAllocateZeroPool (
583 IN EFI_MEMORY_TYPE PoolType
,
584 IN UINTN AllocationSize
589 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
590 if (Memory
!= NULL
) {
591 Memory
= ZeroMem (Memory
, AllocationSize
);
598 UncachedAllocateZeroPool (
599 IN UINTN AllocationSize
602 return UncachedInternalAllocateZeroPool (EfiBootServicesData
, AllocationSize
);
607 UncachedAllocateRuntimeZeroPool (
608 IN UINTN AllocationSize
611 return UncachedInternalAllocateZeroPool (EfiRuntimeServicesData
, AllocationSize
);
616 UncachedAllocateReservedZeroPool (
617 IN UINTN AllocationSize
620 return UncachedInternalAllocateZeroPool (EfiReservedMemoryType
, AllocationSize
);
624 UncachedInternalAllocateCopyPool (
625 IN EFI_MEMORY_TYPE PoolType
,
626 IN UINTN AllocationSize
,
627 IN CONST VOID
*Buffer
632 ASSERT (Buffer
!= NULL
);
633 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
635 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
636 if (Memory
!= NULL
) {
637 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
644 UncachedAllocateCopyPool (
645 IN UINTN AllocationSize
,
646 IN CONST VOID
*Buffer
649 return UncachedInternalAllocateCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
);
654 UncachedAllocateRuntimeCopyPool (
655 IN UINTN AllocationSize
,
656 IN CONST VOID
*Buffer
659 return UncachedInternalAllocateCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
);
664 UncachedAllocateReservedCopyPool (
665 IN UINTN AllocationSize
,
666 IN CONST VOID
*Buffer
669 return UncachedInternalAllocateCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
);
678 UncachedFreeAlignedPool (Buffer
);
683 UncachedSafeFreePool (
687 if (Buffer
!= NULL
) {
688 UncachedFreePool (Buffer
);