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 EFI_PHYSICAL_ADDRESS Base
;
49 EFI_MEMORY_TYPE MemoryType
;
55 STATIC LIST_ENTRY mPageList
= INITIALIZE_LIST_HEAD_VARIABLE (mPageList
);
56 // Track the size of the non-allocated buffer in the linked-list
57 STATIC UINTN mFreedBufferSize
= 0;
60 * This function firstly checks if the requested allocation can fit into one
61 * of the previously allocated buffer.
62 * If the requested allocation does not fit in the existing pool then
63 * the function makes a new allocation.
65 * @param MemoryType Type of memory requested for the new allocation
66 * @param Pages Number of requested page
67 * @param Alignment Required alignment
68 * @param Allocation Address of the newly allocated buffer
70 * @return EFI_SUCCESS If the function manage to allocate a buffer
71 * @return !EFI_SUCCESS If the function did not manage to allocate a buffer
75 AllocatePagesFromList (
76 IN EFI_MEMORY_TYPE MemoryType
,
85 FREE_PAGE_NODE
*NewNode
;
87 EFI_PHYSICAL_ADDRESS Memory
;
88 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
90 // Alignment must be a power of two or zero.
91 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
94 // Look in our list for the smallest page that could satisfy the new allocation
98 for (Link
= mPageList
.ForwardLink
; Link
!= &mPageList
; Link
= Link
->ForwardLink
) {
99 Node
= BASE_CR (Link
, FREE_PAGE_NODE
, Link
);
100 if ((Node
->Allocated
== FALSE
) && (Node
->MemoryType
== MemoryType
)) {
101 // We have a node that fits our requirements
102 if (((UINTN
)Node
->Base
& (Alignment
- 1)) == 0) {
103 // We found a page that matches the page size
104 if (Node
->Pages
== Pages
) {
105 Node
->Allocated
= TRUE
;
106 Node
->Allocation
= (VOID
*)(UINTN
)Node
->Base
;
107 *Allocation
= Node
->Allocation
;
109 // Update the size of the freed buffer
110 mFreedBufferSize
-= Pages
* EFI_PAGE_SIZE
;
112 } else if (Node
->Pages
> Pages
) {
113 if (NewNode
== NULL
) {
114 // It is the first node that could contain our new allocation
116 } else if (NewNode
->Pages
> Node
->Pages
) {
117 // This node offers a smaller number of page.
124 // Check if we have found a node that could contain our new allocation
125 if (NewNode
!= NULL
) {
126 NewNode
->Allocated
= TRUE
;
127 NewNode
->Allocation
= (VOID
*)(UINTN
)NewNode
->Base
;
128 *Allocation
= NewNode
->Allocation
;
129 mFreedBufferSize
-= NewNode
->Pages
* EFI_PAGE_SIZE
;
134 // Otherwise, we need to allocate a new buffer
137 // We do not want to over-allocate in case the alignment requirement does not
138 // require extra pages
139 if (Alignment
> EFI_PAGE_SIZE
) {
140 AlignmentMask
= Alignment
- 1;
141 Pages
+= EFI_SIZE_TO_PAGES (Alignment
);
146 Status
= gBS
->AllocatePages (AllocateAnyPages
, MemoryType
, Pages
, &Memory
);
147 if (EFI_ERROR (Status
)) {
151 Status
= gDS
->GetMemorySpaceDescriptor (Memory
, &Descriptor
);
152 if (EFI_ERROR (Status
)) {
153 gBS
->FreePages (Memory
, Pages
);
157 Status
= gDS
->SetMemorySpaceAttributes (Memory
, EFI_PAGES_TO_SIZE (Pages
),
158 EFI_MEMORY_WC
| EFI_MEMORY_XP
);
159 if (EFI_ERROR (Status
)) {
160 gBS
->FreePages (Memory
, Pages
);
164 InvalidateDataCacheRange ((VOID
*)(UINTN
)Memory
, EFI_PAGES_TO_SIZE (Pages
));
166 NewNode
= AllocatePool (sizeof (FREE_PAGE_NODE
));
167 if (NewNode
== NULL
) {
169 gBS
->FreePages (Memory
, Pages
);
170 return EFI_OUT_OF_RESOURCES
;
173 NewNode
->Base
= Memory
;
174 NewNode
->Allocation
= (VOID
*)(((UINTN
)Memory
+ AlignmentMask
) & ~AlignmentMask
);
175 NewNode
->Pages
= Pages
;
176 NewNode
->Allocated
= TRUE
;
177 NewNode
->MemoryType
= MemoryType
;
178 NewNode
->Attributes
= Descriptor
.Attributes
;
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
);
265 gDS
->SetMemorySpaceAttributes ((EFI_PHYSICAL_ADDRESS
)(UINTN
)OldNode
->Base
,
266 EFI_PAGES_TO_SIZE (OldNode
->Pages
), OldNode
->Attributes
);
268 RemoveEntryList (&OldNode
->Link
);
271 } while (Link
!= &mPageList
);
277 Converts a cached or uncached address to a physical address suitable for use in SoC registers.
279 @param VirtualAddress The pointer to convert.
281 @return The physical address of the supplied virtual pointer.
285 ConvertToPhysicalAddress (
286 IN VOID
*VirtualAddress
289 return (EFI_PHYSICAL_ADDRESS
)(UINTN
)VirtualAddress
;
294 UncachedInternalAllocatePages (
295 IN EFI_MEMORY_TYPE MemoryType
,
299 return UncachedInternalAllocateAlignedPages (MemoryType
, Pages
, EFI_PAGE_SIZE
);
305 UncachedAllocatePages (
309 return UncachedInternalAllocatePages (EfiBootServicesData
, Pages
);
314 UncachedAllocateRuntimePages (
318 return UncachedInternalAllocatePages (EfiRuntimeServicesData
, Pages
);
323 UncachedAllocateReservedPages (
327 return UncachedInternalAllocatePages (EfiReservedMemoryType
, Pages
);
339 UncachedFreeAlignedPages (Buffer
, Pages
);
345 UncachedInternalAllocateAlignedPages (
346 IN EFI_MEMORY_TYPE MemoryType
,
359 Status
= AllocatePagesFromList (MemoryType
, Pages
, Alignment
, &Allocation
);
360 if (EFI_ERROR (Status
)) {
361 ASSERT_EFI_ERROR (Status
);
371 UncachedFreeAlignedPages (
376 FreePagesFromList (Buffer
);
381 UncachedInternalAllocateAlignedPool (
382 IN EFI_MEMORY_TYPE PoolType
,
383 IN UINTN AllocationSize
,
387 VOID
*AlignedAddress
;
390 // Alignment must be a power of two or zero.
392 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
394 if (Alignment
< EFI_PAGE_SIZE
) {
395 Alignment
= EFI_PAGE_SIZE
;
398 AlignedAddress
= UncachedInternalAllocateAlignedPages (PoolType
, EFI_SIZE_TO_PAGES (AllocationSize
), Alignment
);
399 if (AlignedAddress
== NULL
) {
403 return (VOID
*) AlignedAddress
;
408 UncachedAllocateAlignedPool (
409 IN UINTN AllocationSize
,
413 return UncachedInternalAllocateAlignedPool (EfiBootServicesData
, AllocationSize
, Alignment
);
418 UncachedAllocateAlignedRuntimePool (
419 IN UINTN AllocationSize
,
423 return UncachedInternalAllocateAlignedPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
428 UncachedAllocateAlignedReservedPool (
429 IN UINTN AllocationSize
,
433 return UncachedInternalAllocateAlignedPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
437 UncachedInternalAllocateAlignedZeroPool (
438 IN EFI_MEMORY_TYPE PoolType
,
439 IN UINTN AllocationSize
,
444 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
445 if (Memory
!= NULL
) {
446 Memory
= ZeroMem (Memory
, AllocationSize
);
453 UncachedAllocateAlignedZeroPool (
454 IN UINTN AllocationSize
,
458 return UncachedInternalAllocateAlignedZeroPool (EfiBootServicesData
, AllocationSize
, Alignment
);
463 UncachedAllocateAlignedRuntimeZeroPool (
464 IN UINTN AllocationSize
,
468 return UncachedInternalAllocateAlignedZeroPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
473 UncachedAllocateAlignedReservedZeroPool (
474 IN UINTN AllocationSize
,
478 return UncachedInternalAllocateAlignedZeroPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
482 UncachedInternalAllocateAlignedCopyPool (
483 IN EFI_MEMORY_TYPE PoolType
,
484 IN UINTN AllocationSize
,
485 IN CONST VOID
*Buffer
,
491 ASSERT (Buffer
!= NULL
);
492 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
494 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
495 if (Memory
!= NULL
) {
496 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
503 UncachedAllocateAlignedCopyPool (
504 IN UINTN AllocationSize
,
505 IN CONST VOID
*Buffer
,
509 return UncachedInternalAllocateAlignedCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
, Alignment
);
514 UncachedAllocateAlignedRuntimeCopyPool (
515 IN UINTN AllocationSize
,
516 IN CONST VOID
*Buffer
,
520 return UncachedInternalAllocateAlignedCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
, Alignment
);
525 UncachedAllocateAlignedReservedCopyPool (
526 IN UINTN AllocationSize
,
527 IN CONST VOID
*Buffer
,
531 return UncachedInternalAllocateAlignedCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
, Alignment
);
536 UncachedFreeAlignedPool (
540 UncachedFreePages (Allocation
, 0);
544 UncachedInternalAllocatePool (
545 IN EFI_MEMORY_TYPE MemoryType
,
546 IN UINTN AllocationSize
549 UINTN CacheLineLength
= ArmCacheWritebackGranule ();
550 return UncachedInternalAllocateAlignedPool (MemoryType
, AllocationSize
, CacheLineLength
);
555 UncachedAllocatePool (
556 IN UINTN AllocationSize
559 return UncachedInternalAllocatePool (EfiBootServicesData
, AllocationSize
);
564 UncachedAllocateRuntimePool (
565 IN UINTN AllocationSize
568 return UncachedInternalAllocatePool (EfiRuntimeServicesData
, AllocationSize
);
573 UncachedAllocateReservedPool (
574 IN UINTN AllocationSize
577 return UncachedInternalAllocatePool (EfiReservedMemoryType
, AllocationSize
);
581 UncachedInternalAllocateZeroPool (
582 IN EFI_MEMORY_TYPE PoolType
,
583 IN UINTN AllocationSize
588 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
589 if (Memory
!= NULL
) {
590 Memory
= ZeroMem (Memory
, AllocationSize
);
597 UncachedAllocateZeroPool (
598 IN UINTN AllocationSize
601 return UncachedInternalAllocateZeroPool (EfiBootServicesData
, AllocationSize
);
606 UncachedAllocateRuntimeZeroPool (
607 IN UINTN AllocationSize
610 return UncachedInternalAllocateZeroPool (EfiRuntimeServicesData
, AllocationSize
);
615 UncachedAllocateReservedZeroPool (
616 IN UINTN AllocationSize
619 return UncachedInternalAllocateZeroPool (EfiReservedMemoryType
, AllocationSize
);
623 UncachedInternalAllocateCopyPool (
624 IN EFI_MEMORY_TYPE PoolType
,
625 IN UINTN AllocationSize
,
626 IN CONST VOID
*Buffer
631 ASSERT (Buffer
!= NULL
);
632 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
634 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
635 if (Memory
!= NULL
) {
636 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
643 UncachedAllocateCopyPool (
644 IN UINTN AllocationSize
,
645 IN CONST VOID
*Buffer
648 return UncachedInternalAllocateCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
);
653 UncachedAllocateRuntimeCopyPool (
654 IN UINTN AllocationSize
,
655 IN CONST VOID
*Buffer
658 return UncachedInternalAllocateCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
);
663 UncachedAllocateReservedCopyPool (
664 IN UINTN AllocationSize
,
665 IN CONST VOID
*Buffer
668 return UncachedInternalAllocateCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
);
677 UncachedFreeAlignedPool (Buffer
);
682 UncachedSafeFreePool (
686 if (Buffer
!= NULL
) {
687 UncachedFreePool (Buffer
);