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>
30 UncachedInternalAllocatePages (
31 IN EFI_MEMORY_TYPE MemoryType
,
36 UncachedInternalAllocateAlignedPages (
37 IN EFI_MEMORY_TYPE MemoryType
,
45 // Assume all of memory has the same cache attributes, unless we do our magic
50 EFI_PHYSICAL_ADDRESS Base
;
53 EFI_MEMORY_TYPE MemoryType
;
58 STATIC LIST_ENTRY mPageList
= INITIALIZE_LIST_HEAD_VARIABLE (mPageList
);
59 // Track the size of the non-allocated buffer in the linked-list
60 STATIC UINTN mFreedBufferSize
= 0;
63 * This function firstly checks if the requested allocation can fit into one
64 * of the previously allocated buffer.
65 * If the requested allocation does not fit in the existing pool then
66 * the function makes a new allocation.
68 * @param MemoryType Type of memory requested for the new allocation
69 * @param Pages Number of requested page
70 * @param Alignment Required alignment
71 * @param Allocation Address of the newly allocated buffer
73 * @return EFI_SUCCESS If the function manage to allocate a buffer
74 * @return !EFI_SUCCESS If the function did not manage to allocate a buffer
78 AllocatePagesFromList (
79 IN EFI_MEMORY_TYPE MemoryType
,
88 FREE_PAGE_NODE
*NewNode
;
90 EFI_PHYSICAL_ADDRESS Memory
;
91 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
93 // Alignment must be a power of two or zero.
94 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
97 // Look in our list for the smallest page that could satisfy the new allocation
100 for (Link
= mPageList
.ForwardLink
; Link
!= &mPageList
; Link
= Link
->ForwardLink
) {
101 Node
= BASE_CR (Link
, FREE_PAGE_NODE
, Link
);
102 if ((Node
->Allocated
== FALSE
) && (Node
->MemoryType
== MemoryType
)) {
103 // We have a node that fits our requirements
104 if (((UINTN
)Node
->Base
& (Alignment
- 1)) == 0) {
105 // We found a page that matches the page size
106 if (Node
->Pages
== Pages
) {
107 Node
->Allocated
= TRUE
;
108 Node
->Allocation
= (VOID
*)(UINTN
)Node
->Base
;
109 *Allocation
= Node
->Allocation
;
111 // Update the size of the freed buffer
112 mFreedBufferSize
-= Pages
* EFI_PAGE_SIZE
;
114 } else if (Node
->Pages
> Pages
) {
115 if (NewNode
== NULL
) {
116 // It is the first node that could contain our new allocation
118 } else if (NewNode
->Pages
> Node
->Pages
) {
119 // This node offers a smaller number of page.
126 // Check if we have found a node that could contain our new allocation
127 if (NewNode
!= NULL
) {
128 NewNode
->Allocated
= TRUE
;
129 Node
->Allocation
= (VOID
*)(UINTN
)Node
->Base
;
130 *Allocation
= Node
->Allocation
;
135 // Otherwise, we need to allocate a new buffer
138 // We do not want to over-allocate in case the alignment requirement does not
139 // require extra pages
140 if (Alignment
> EFI_PAGE_SIZE
) {
141 AlignmentMask
= Alignment
- 1;
142 Pages
+= EFI_SIZE_TO_PAGES (Alignment
);
147 Status
= gBS
->AllocatePages (AllocateAnyPages
, MemoryType
, Pages
, &Memory
);
148 if (EFI_ERROR (Status
)) {
152 Status
= gDS
->GetMemorySpaceDescriptor (Memory
, &Descriptor
);
153 if (!EFI_ERROR (Status
)) {
154 // We are making an assumption that all of memory has the same default attributes
155 gAttributes
= Descriptor
.Attributes
;
157 gBS
->FreePages (Memory
, Pages
);
161 Status
= gDS
->SetMemorySpaceAttributes (Memory
, EFI_PAGES_TO_SIZE (Pages
), EFI_MEMORY_WC
);
162 if (EFI_ERROR (Status
)) {
163 gBS
->FreePages (Memory
, Pages
);
167 NewNode
= AllocatePool (sizeof (FREE_PAGE_NODE
));
168 if (NewNode
== NULL
) {
170 gBS
->FreePages (Memory
, Pages
);
171 return EFI_OUT_OF_RESOURCES
;
174 NewNode
->Base
= Memory
;
175 NewNode
->Allocation
= (VOID
*)(((UINTN
)Memory
+ AlignmentMask
) & ~AlignmentMask
);
176 NewNode
->Pages
= Pages
;
177 NewNode
->Allocated
= TRUE
;
178 NewNode
->MemoryType
= MemoryType
;
180 InsertTailList (&mPageList
, &NewNode
->Link
);
182 *Allocation
= NewNode
->Allocation
;
187 * Free the memory allocation
189 * This function will actually try to find the allocation in the linked list.
190 * And it will then mark the entry as freed.
192 * @param Allocation Base address of the buffer to free
194 * @return EFI_SUCCESS The allocation has been freed
195 * @return EFI_NOT_FOUND The allocation was not found in the pool.
196 * @return EFI_INVALID_PARAMETER If Allocation is NULL
206 FREE_PAGE_NODE
*Node
;
208 if (Allocation
== NULL
) {
209 return EFI_INVALID_PARAMETER
;
212 for (Link
= mPageList
.ForwardLink
; Link
!= &mPageList
; Link
= Link
->ForwardLink
) {
213 Node
= BASE_CR (Link
, FREE_PAGE_NODE
, Link
);
214 if ((UINTN
)Node
->Allocation
== (UINTN
)Allocation
) {
215 Node
->Allocated
= FALSE
;
217 // Update the size of the freed buffer
218 mFreedBufferSize
+= Node
->Pages
* EFI_PAGE_SIZE
;
220 // If the size of the non-allocated reaches the threshold we raise a warning.
221 // It might be an expected behaviour in some cases.
222 // We might device to free some of these buffers later on.
223 if (mFreedBufferSize
> PcdGet64 (PcdArmFreeUncachedMemorySizeThreshold
)) {
224 DEBUG ((EFI_D_WARN
, "Warning: The list of non-allocated buffer has reach the threshold.\n"));
230 return EFI_NOT_FOUND
;
234 * This function is automatically invoked when the driver exits
235 * It frees all the non-allocated memory buffer.
236 * This function is not responsible to free allocated buffer (eg: case of memory leak,
237 * runtime allocation).
241 UncachedMemoryAllocationLibDestructor (
242 IN EFI_HANDLE ImageHandle
,
243 IN EFI_SYSTEM_TABLE
*SystemTable
247 FREE_PAGE_NODE
*OldNode
;
249 // Test if the list is empty
250 Link
= mPageList
.ForwardLink
;
251 if (Link
== &mPageList
) {
255 // Free all the pages and nodes
257 OldNode
= BASE_CR (Link
, FREE_PAGE_NODE
, Link
);
258 // Point to the next entry
259 Link
= Link
->ForwardLink
;
261 // We only free the non-allocated buffer
262 if (OldNode
->Allocated
== FALSE
) {
263 gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
)(UINTN
)OldNode
->Base
, OldNode
->Pages
);
264 RemoveEntryList (&OldNode
->Link
);
267 } while (Link
!= &mPageList
);
273 Converts a cached or uncached address to a physical address suitable for use in SoC registers.
275 @param VirtualAddress The pointer to convert.
277 @return The physical address of the supplied virtual pointer.
281 ConvertToPhysicalAddress (
282 IN VOID
*VirtualAddress
285 return (EFI_PHYSICAL_ADDRESS
)(UINTN
)VirtualAddress
;
290 UncachedInternalAllocatePages (
291 IN EFI_MEMORY_TYPE MemoryType
,
295 return UncachedInternalAllocateAlignedPages (MemoryType
, Pages
, EFI_PAGE_SIZE
);
301 UncachedAllocatePages (
305 return UncachedInternalAllocatePages (EfiBootServicesData
, Pages
);
310 UncachedAllocateRuntimePages (
314 return UncachedInternalAllocatePages (EfiRuntimeServicesData
, Pages
);
319 UncachedAllocateReservedPages (
323 return UncachedInternalAllocatePages (EfiReservedMemoryType
, Pages
);
335 UncachedFreeAlignedPages (Buffer
, Pages
);
341 UncachedInternalAllocateAlignedPages (
342 IN EFI_MEMORY_TYPE MemoryType
,
355 Status
= AllocatePagesFromList (MemoryType
, Pages
, Alignment
, &Allocation
);
356 if (EFI_ERROR (Status
)) {
357 ASSERT_EFI_ERROR (Status
);
367 UncachedFreeAlignedPages (
372 FreePagesFromList (Buffer
);
377 UncachedInternalAllocateAlignedPool (
378 IN EFI_MEMORY_TYPE PoolType
,
379 IN UINTN AllocationSize
,
383 VOID
*AlignedAddress
;
386 // Alignment must be a power of two or zero.
388 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
390 if (Alignment
< EFI_PAGE_SIZE
) {
391 Alignment
= EFI_PAGE_SIZE
;
394 AlignedAddress
= UncachedInternalAllocateAlignedPages (PoolType
, EFI_SIZE_TO_PAGES (AllocationSize
), Alignment
);
395 if (AlignedAddress
== NULL
) {
399 return (VOID
*) AlignedAddress
;
404 UncachedAllocateAlignedPool (
405 IN UINTN AllocationSize
,
409 return UncachedInternalAllocateAlignedPool (EfiBootServicesData
, AllocationSize
, Alignment
);
414 UncachedAllocateAlignedRuntimePool (
415 IN UINTN AllocationSize
,
419 return UncachedInternalAllocateAlignedPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
424 UncachedAllocateAlignedReservedPool (
425 IN UINTN AllocationSize
,
429 return UncachedInternalAllocateAlignedPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
433 UncachedInternalAllocateAlignedZeroPool (
434 IN EFI_MEMORY_TYPE PoolType
,
435 IN UINTN AllocationSize
,
440 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
441 if (Memory
!= NULL
) {
442 Memory
= ZeroMem (Memory
, AllocationSize
);
449 UncachedAllocateAlignedZeroPool (
450 IN UINTN AllocationSize
,
454 return UncachedInternalAllocateAlignedZeroPool (EfiBootServicesData
, AllocationSize
, Alignment
);
459 UncachedAllocateAlignedRuntimeZeroPool (
460 IN UINTN AllocationSize
,
464 return UncachedInternalAllocateAlignedZeroPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
469 UncachedAllocateAlignedReservedZeroPool (
470 IN UINTN AllocationSize
,
474 return UncachedInternalAllocateAlignedZeroPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
478 UncachedInternalAllocateAlignedCopyPool (
479 IN EFI_MEMORY_TYPE PoolType
,
480 IN UINTN AllocationSize
,
481 IN CONST VOID
*Buffer
,
487 ASSERT (Buffer
!= NULL
);
488 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
490 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
491 if (Memory
!= NULL
) {
492 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
499 UncachedAllocateAlignedCopyPool (
500 IN UINTN AllocationSize
,
501 IN CONST VOID
*Buffer
,
505 return UncachedInternalAllocateAlignedCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
, Alignment
);
510 UncachedAllocateAlignedRuntimeCopyPool (
511 IN UINTN AllocationSize
,
512 IN CONST VOID
*Buffer
,
516 return UncachedInternalAllocateAlignedCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
, Alignment
);
521 UncachedAllocateAlignedReservedCopyPool (
522 IN UINTN AllocationSize
,
523 IN CONST VOID
*Buffer
,
527 return UncachedInternalAllocateAlignedCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
, Alignment
);
532 UncachedFreeAlignedPool (
536 UncachedFreePages (Allocation
, 0);
540 UncachedInternalAllocatePool (
541 IN EFI_MEMORY_TYPE MemoryType
,
542 IN UINTN AllocationSize
545 UINTN CacheLineLength
= ArmDataCacheLineLength ();
546 return UncachedInternalAllocateAlignedPool (MemoryType
, AllocationSize
, CacheLineLength
);
551 UncachedAllocatePool (
552 IN UINTN AllocationSize
555 return UncachedInternalAllocatePool (EfiBootServicesData
, AllocationSize
);
560 UncachedAllocateRuntimePool (
561 IN UINTN AllocationSize
564 return UncachedInternalAllocatePool (EfiRuntimeServicesData
, AllocationSize
);
569 UncachedAllocateReservedPool (
570 IN UINTN AllocationSize
573 return UncachedInternalAllocatePool (EfiReservedMemoryType
, AllocationSize
);
577 UncachedInternalAllocateZeroPool (
578 IN EFI_MEMORY_TYPE PoolType
,
579 IN UINTN AllocationSize
584 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
585 if (Memory
!= NULL
) {
586 Memory
= ZeroMem (Memory
, AllocationSize
);
593 UncachedAllocateZeroPool (
594 IN UINTN AllocationSize
597 return UncachedInternalAllocateZeroPool (EfiBootServicesData
, AllocationSize
);
602 UncachedAllocateRuntimeZeroPool (
603 IN UINTN AllocationSize
606 return UncachedInternalAllocateZeroPool (EfiRuntimeServicesData
, AllocationSize
);
611 UncachedAllocateReservedZeroPool (
612 IN UINTN AllocationSize
615 return UncachedInternalAllocateZeroPool (EfiReservedMemoryType
, AllocationSize
);
619 UncachedInternalAllocateCopyPool (
620 IN EFI_MEMORY_TYPE PoolType
,
621 IN UINTN AllocationSize
,
622 IN CONST VOID
*Buffer
627 ASSERT (Buffer
!= NULL
);
628 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
630 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
631 if (Memory
!= NULL
) {
632 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
639 UncachedAllocateCopyPool (
640 IN UINTN AllocationSize
,
641 IN CONST VOID
*Buffer
644 return UncachedInternalAllocateCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
);
649 UncachedAllocateRuntimeCopyPool (
650 IN UINTN AllocationSize
,
651 IN CONST VOID
*Buffer
654 return UncachedInternalAllocateCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
);
659 UncachedAllocateReservedCopyPool (
660 IN UINTN AllocationSize
,
661 IN CONST VOID
*Buffer
664 return UncachedInternalAllocateCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
);
673 UncachedFreeAlignedPool (Buffer
);
678 UncachedSafeFreePool (
682 if (Buffer
!= NULL
) {
683 UncachedFreePool (Buffer
);