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
), EFI_MEMORY_WC
);
158 if (EFI_ERROR (Status
)) {
159 gBS
->FreePages (Memory
, Pages
);
163 InvalidateDataCacheRange ((VOID
*)(UINTN
)Memory
, EFI_PAGES_TO_SIZE (Pages
));
165 NewNode
= AllocatePool (sizeof (FREE_PAGE_NODE
));
166 if (NewNode
== NULL
) {
168 gBS
->FreePages (Memory
, Pages
);
169 return EFI_OUT_OF_RESOURCES
;
172 NewNode
->Base
= Memory
;
173 NewNode
->Allocation
= (VOID
*)(((UINTN
)Memory
+ AlignmentMask
) & ~AlignmentMask
);
174 NewNode
->Pages
= Pages
;
175 NewNode
->Allocated
= TRUE
;
176 NewNode
->MemoryType
= MemoryType
;
177 NewNode
->Attributes
= Descriptor
.Attributes
;
179 InsertTailList (&mPageList
, &NewNode
->Link
);
181 *Allocation
= NewNode
->Allocation
;
186 * Free the memory allocation
188 * This function will actually try to find the allocation in the linked list.
189 * And it will then mark the entry as freed.
191 * @param Allocation Base address of the buffer to free
193 * @return EFI_SUCCESS The allocation has been freed
194 * @return EFI_NOT_FOUND The allocation was not found in the pool.
195 * @return EFI_INVALID_PARAMETER If Allocation is NULL
205 FREE_PAGE_NODE
*Node
;
207 if (Allocation
== NULL
) {
208 return EFI_INVALID_PARAMETER
;
211 for (Link
= mPageList
.ForwardLink
; Link
!= &mPageList
; Link
= Link
->ForwardLink
) {
212 Node
= BASE_CR (Link
, FREE_PAGE_NODE
, Link
);
213 if ((UINTN
)Node
->Allocation
== (UINTN
)Allocation
) {
214 Node
->Allocated
= FALSE
;
216 // Update the size of the freed buffer
217 mFreedBufferSize
+= Node
->Pages
* EFI_PAGE_SIZE
;
219 // If the size of the non-allocated reaches the threshold we raise a warning.
220 // It might be an expected behaviour in some cases.
221 // We might device to free some of these buffers later on.
222 if (mFreedBufferSize
> PcdGet64 (PcdArmFreeUncachedMemorySizeThreshold
)) {
223 DEBUG ((EFI_D_WARN
, "Warning: The list of non-allocated buffer has reach the threshold.\n"));
229 return EFI_NOT_FOUND
;
233 * This function is automatically invoked when the driver exits
234 * It frees all the non-allocated memory buffer.
235 * This function is not responsible to free allocated buffer (eg: case of memory leak,
236 * runtime allocation).
240 UncachedMemoryAllocationLibDestructor (
241 IN EFI_HANDLE ImageHandle
,
242 IN EFI_SYSTEM_TABLE
*SystemTable
246 FREE_PAGE_NODE
*OldNode
;
248 // Test if the list is empty
249 Link
= mPageList
.ForwardLink
;
250 if (Link
== &mPageList
) {
254 // Free all the pages and nodes
256 OldNode
= BASE_CR (Link
, FREE_PAGE_NODE
, Link
);
257 // Point to the next entry
258 Link
= Link
->ForwardLink
;
260 // We only free the non-allocated buffer
261 if (OldNode
->Allocated
== FALSE
) {
262 gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
)(UINTN
)OldNode
->Base
, OldNode
->Pages
);
264 gDS
->SetMemorySpaceAttributes ((EFI_PHYSICAL_ADDRESS
)(UINTN
)OldNode
->Base
,
265 EFI_PAGES_TO_SIZE (OldNode
->Pages
), OldNode
->Attributes
);
267 RemoveEntryList (&OldNode
->Link
);
270 } while (Link
!= &mPageList
);
276 Converts a cached or uncached address to a physical address suitable for use in SoC registers.
278 @param VirtualAddress The pointer to convert.
280 @return The physical address of the supplied virtual pointer.
284 ConvertToPhysicalAddress (
285 IN VOID
*VirtualAddress
288 return (EFI_PHYSICAL_ADDRESS
)(UINTN
)VirtualAddress
;
293 UncachedInternalAllocatePages (
294 IN EFI_MEMORY_TYPE MemoryType
,
298 return UncachedInternalAllocateAlignedPages (MemoryType
, Pages
, EFI_PAGE_SIZE
);
304 UncachedAllocatePages (
308 return UncachedInternalAllocatePages (EfiBootServicesData
, Pages
);
313 UncachedAllocateRuntimePages (
317 return UncachedInternalAllocatePages (EfiRuntimeServicesData
, Pages
);
322 UncachedAllocateReservedPages (
326 return UncachedInternalAllocatePages (EfiReservedMemoryType
, Pages
);
338 UncachedFreeAlignedPages (Buffer
, Pages
);
344 UncachedInternalAllocateAlignedPages (
345 IN EFI_MEMORY_TYPE MemoryType
,
358 Status
= AllocatePagesFromList (MemoryType
, Pages
, Alignment
, &Allocation
);
359 if (EFI_ERROR (Status
)) {
360 ASSERT_EFI_ERROR (Status
);
370 UncachedFreeAlignedPages (
375 FreePagesFromList (Buffer
);
380 UncachedInternalAllocateAlignedPool (
381 IN EFI_MEMORY_TYPE PoolType
,
382 IN UINTN AllocationSize
,
386 VOID
*AlignedAddress
;
389 // Alignment must be a power of two or zero.
391 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
393 if (Alignment
< EFI_PAGE_SIZE
) {
394 Alignment
= EFI_PAGE_SIZE
;
397 AlignedAddress
= UncachedInternalAllocateAlignedPages (PoolType
, EFI_SIZE_TO_PAGES (AllocationSize
), Alignment
);
398 if (AlignedAddress
== NULL
) {
402 return (VOID
*) AlignedAddress
;
407 UncachedAllocateAlignedPool (
408 IN UINTN AllocationSize
,
412 return UncachedInternalAllocateAlignedPool (EfiBootServicesData
, AllocationSize
, Alignment
);
417 UncachedAllocateAlignedRuntimePool (
418 IN UINTN AllocationSize
,
422 return UncachedInternalAllocateAlignedPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
427 UncachedAllocateAlignedReservedPool (
428 IN UINTN AllocationSize
,
432 return UncachedInternalAllocateAlignedPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
436 UncachedInternalAllocateAlignedZeroPool (
437 IN EFI_MEMORY_TYPE PoolType
,
438 IN UINTN AllocationSize
,
443 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
444 if (Memory
!= NULL
) {
445 Memory
= ZeroMem (Memory
, AllocationSize
);
452 UncachedAllocateAlignedZeroPool (
453 IN UINTN AllocationSize
,
457 return UncachedInternalAllocateAlignedZeroPool (EfiBootServicesData
, AllocationSize
, Alignment
);
462 UncachedAllocateAlignedRuntimeZeroPool (
463 IN UINTN AllocationSize
,
467 return UncachedInternalAllocateAlignedZeroPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
472 UncachedAllocateAlignedReservedZeroPool (
473 IN UINTN AllocationSize
,
477 return UncachedInternalAllocateAlignedZeroPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
481 UncachedInternalAllocateAlignedCopyPool (
482 IN EFI_MEMORY_TYPE PoolType
,
483 IN UINTN AllocationSize
,
484 IN CONST VOID
*Buffer
,
490 ASSERT (Buffer
!= NULL
);
491 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
493 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
494 if (Memory
!= NULL
) {
495 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
502 UncachedAllocateAlignedCopyPool (
503 IN UINTN AllocationSize
,
504 IN CONST VOID
*Buffer
,
508 return UncachedInternalAllocateAlignedCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
, Alignment
);
513 UncachedAllocateAlignedRuntimeCopyPool (
514 IN UINTN AllocationSize
,
515 IN CONST VOID
*Buffer
,
519 return UncachedInternalAllocateAlignedCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
, Alignment
);
524 UncachedAllocateAlignedReservedCopyPool (
525 IN UINTN AllocationSize
,
526 IN CONST VOID
*Buffer
,
530 return UncachedInternalAllocateAlignedCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
, Alignment
);
535 UncachedFreeAlignedPool (
539 UncachedFreePages (Allocation
, 0);
543 UncachedInternalAllocatePool (
544 IN EFI_MEMORY_TYPE MemoryType
,
545 IN UINTN AllocationSize
548 UINTN CacheLineLength
= ArmCacheWritebackGranule ();
549 return UncachedInternalAllocateAlignedPool (MemoryType
, AllocationSize
, CacheLineLength
);
554 UncachedAllocatePool (
555 IN UINTN AllocationSize
558 return UncachedInternalAllocatePool (EfiBootServicesData
, AllocationSize
);
563 UncachedAllocateRuntimePool (
564 IN UINTN AllocationSize
567 return UncachedInternalAllocatePool (EfiRuntimeServicesData
, AllocationSize
);
572 UncachedAllocateReservedPool (
573 IN UINTN AllocationSize
576 return UncachedInternalAllocatePool (EfiReservedMemoryType
, AllocationSize
);
580 UncachedInternalAllocateZeroPool (
581 IN EFI_MEMORY_TYPE PoolType
,
582 IN UINTN AllocationSize
587 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
588 if (Memory
!= NULL
) {
589 Memory
= ZeroMem (Memory
, AllocationSize
);
596 UncachedAllocateZeroPool (
597 IN UINTN AllocationSize
600 return UncachedInternalAllocateZeroPool (EfiBootServicesData
, AllocationSize
);
605 UncachedAllocateRuntimeZeroPool (
606 IN UINTN AllocationSize
609 return UncachedInternalAllocateZeroPool (EfiRuntimeServicesData
, AllocationSize
);
614 UncachedAllocateReservedZeroPool (
615 IN UINTN AllocationSize
618 return UncachedInternalAllocateZeroPool (EfiReservedMemoryType
, AllocationSize
);
622 UncachedInternalAllocateCopyPool (
623 IN EFI_MEMORY_TYPE PoolType
,
624 IN UINTN AllocationSize
,
625 IN CONST VOID
*Buffer
630 ASSERT (Buffer
!= NULL
);
631 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
633 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
634 if (Memory
!= NULL
) {
635 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
642 UncachedAllocateCopyPool (
643 IN UINTN AllocationSize
,
644 IN CONST VOID
*Buffer
647 return UncachedInternalAllocateCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
);
652 UncachedAllocateRuntimeCopyPool (
653 IN UINTN AllocationSize
,
654 IN CONST VOID
*Buffer
657 return UncachedInternalAllocateCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
);
662 UncachedAllocateReservedCopyPool (
663 IN UINTN AllocationSize
,
664 IN CONST VOID
*Buffer
667 return UncachedInternalAllocateCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
);
676 UncachedFreeAlignedPool (Buffer
);
681 UncachedSafeFreePool (
685 if (Buffer
!= NULL
) {
686 UncachedFreePool (Buffer
);