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 NewNode
->Allocation
= (VOID
*)(UINTN
)NewNode
->Base
;
130 *Allocation
= NewNode
->Allocation
;
131 mFreedBufferSize
-= NewNode
->Pages
* EFI_PAGE_SIZE
;
136 // Otherwise, we need to allocate a new buffer
139 // We do not want to over-allocate in case the alignment requirement does not
140 // require extra pages
141 if (Alignment
> EFI_PAGE_SIZE
) {
142 AlignmentMask
= Alignment
- 1;
143 Pages
+= EFI_SIZE_TO_PAGES (Alignment
);
148 Status
= gBS
->AllocatePages (AllocateAnyPages
, MemoryType
, Pages
, &Memory
);
149 if (EFI_ERROR (Status
)) {
153 Status
= gDS
->GetMemorySpaceDescriptor (Memory
, &Descriptor
);
154 if (!EFI_ERROR (Status
)) {
155 // We are making an assumption that all of memory has the same default attributes
156 gAttributes
= Descriptor
.Attributes
;
158 gBS
->FreePages (Memory
, Pages
);
162 Status
= gDS
->SetMemorySpaceAttributes (Memory
, EFI_PAGES_TO_SIZE (Pages
), EFI_MEMORY_WC
);
163 if (EFI_ERROR (Status
)) {
164 gBS
->FreePages (Memory
, Pages
);
168 NewNode
= AllocatePool (sizeof (FREE_PAGE_NODE
));
169 if (NewNode
== NULL
) {
171 gBS
->FreePages (Memory
, Pages
);
172 return EFI_OUT_OF_RESOURCES
;
175 NewNode
->Base
= Memory
;
176 NewNode
->Allocation
= (VOID
*)(((UINTN
)Memory
+ AlignmentMask
) & ~AlignmentMask
);
177 NewNode
->Pages
= Pages
;
178 NewNode
->Allocated
= TRUE
;
179 NewNode
->MemoryType
= MemoryType
;
181 InsertTailList (&mPageList
, &NewNode
->Link
);
183 *Allocation
= NewNode
->Allocation
;
188 * Free the memory allocation
190 * This function will actually try to find the allocation in the linked list.
191 * And it will then mark the entry as freed.
193 * @param Allocation Base address of the buffer to free
195 * @return EFI_SUCCESS The allocation has been freed
196 * @return EFI_NOT_FOUND The allocation was not found in the pool.
197 * @return EFI_INVALID_PARAMETER If Allocation is NULL
207 FREE_PAGE_NODE
*Node
;
209 if (Allocation
== NULL
) {
210 return EFI_INVALID_PARAMETER
;
213 for (Link
= mPageList
.ForwardLink
; Link
!= &mPageList
; Link
= Link
->ForwardLink
) {
214 Node
= BASE_CR (Link
, FREE_PAGE_NODE
, Link
);
215 if ((UINTN
)Node
->Allocation
== (UINTN
)Allocation
) {
216 Node
->Allocated
= FALSE
;
218 // Update the size of the freed buffer
219 mFreedBufferSize
+= Node
->Pages
* EFI_PAGE_SIZE
;
221 // If the size of the non-allocated reaches the threshold we raise a warning.
222 // It might be an expected behaviour in some cases.
223 // We might device to free some of these buffers later on.
224 if (mFreedBufferSize
> PcdGet64 (PcdArmFreeUncachedMemorySizeThreshold
)) {
225 DEBUG ((EFI_D_WARN
, "Warning: The list of non-allocated buffer has reach the threshold.\n"));
231 return EFI_NOT_FOUND
;
235 * This function is automatically invoked when the driver exits
236 * It frees all the non-allocated memory buffer.
237 * This function is not responsible to free allocated buffer (eg: case of memory leak,
238 * runtime allocation).
242 UncachedMemoryAllocationLibDestructor (
243 IN EFI_HANDLE ImageHandle
,
244 IN EFI_SYSTEM_TABLE
*SystemTable
248 FREE_PAGE_NODE
*OldNode
;
250 // Test if the list is empty
251 Link
= mPageList
.ForwardLink
;
252 if (Link
== &mPageList
) {
256 // Free all the pages and nodes
258 OldNode
= BASE_CR (Link
, FREE_PAGE_NODE
, Link
);
259 // Point to the next entry
260 Link
= Link
->ForwardLink
;
262 // We only free the non-allocated buffer
263 if (OldNode
->Allocated
== FALSE
) {
264 gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
)(UINTN
)OldNode
->Base
, OldNode
->Pages
);
265 RemoveEntryList (&OldNode
->Link
);
268 } while (Link
!= &mPageList
);
274 Converts a cached or uncached address to a physical address suitable for use in SoC registers.
276 @param VirtualAddress The pointer to convert.
278 @return The physical address of the supplied virtual pointer.
282 ConvertToPhysicalAddress (
283 IN VOID
*VirtualAddress
286 return (EFI_PHYSICAL_ADDRESS
)(UINTN
)VirtualAddress
;
291 UncachedInternalAllocatePages (
292 IN EFI_MEMORY_TYPE MemoryType
,
296 return UncachedInternalAllocateAlignedPages (MemoryType
, Pages
, EFI_PAGE_SIZE
);
302 UncachedAllocatePages (
306 return UncachedInternalAllocatePages (EfiBootServicesData
, Pages
);
311 UncachedAllocateRuntimePages (
315 return UncachedInternalAllocatePages (EfiRuntimeServicesData
, Pages
);
320 UncachedAllocateReservedPages (
324 return UncachedInternalAllocatePages (EfiReservedMemoryType
, Pages
);
336 UncachedFreeAlignedPages (Buffer
, Pages
);
342 UncachedInternalAllocateAlignedPages (
343 IN EFI_MEMORY_TYPE MemoryType
,
356 Status
= AllocatePagesFromList (MemoryType
, Pages
, Alignment
, &Allocation
);
357 if (EFI_ERROR (Status
)) {
358 ASSERT_EFI_ERROR (Status
);
368 UncachedFreeAlignedPages (
373 FreePagesFromList (Buffer
);
378 UncachedInternalAllocateAlignedPool (
379 IN EFI_MEMORY_TYPE PoolType
,
380 IN UINTN AllocationSize
,
384 VOID
*AlignedAddress
;
387 // Alignment must be a power of two or zero.
389 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
391 if (Alignment
< EFI_PAGE_SIZE
) {
392 Alignment
= EFI_PAGE_SIZE
;
395 AlignedAddress
= UncachedInternalAllocateAlignedPages (PoolType
, EFI_SIZE_TO_PAGES (AllocationSize
), Alignment
);
396 if (AlignedAddress
== NULL
) {
400 return (VOID
*) AlignedAddress
;
405 UncachedAllocateAlignedPool (
406 IN UINTN AllocationSize
,
410 return UncachedInternalAllocateAlignedPool (EfiBootServicesData
, AllocationSize
, Alignment
);
415 UncachedAllocateAlignedRuntimePool (
416 IN UINTN AllocationSize
,
420 return UncachedInternalAllocateAlignedPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
425 UncachedAllocateAlignedReservedPool (
426 IN UINTN AllocationSize
,
430 return UncachedInternalAllocateAlignedPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
434 UncachedInternalAllocateAlignedZeroPool (
435 IN EFI_MEMORY_TYPE PoolType
,
436 IN UINTN AllocationSize
,
441 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
442 if (Memory
!= NULL
) {
443 Memory
= ZeroMem (Memory
, AllocationSize
);
450 UncachedAllocateAlignedZeroPool (
451 IN UINTN AllocationSize
,
455 return UncachedInternalAllocateAlignedZeroPool (EfiBootServicesData
, AllocationSize
, Alignment
);
460 UncachedAllocateAlignedRuntimeZeroPool (
461 IN UINTN AllocationSize
,
465 return UncachedInternalAllocateAlignedZeroPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
470 UncachedAllocateAlignedReservedZeroPool (
471 IN UINTN AllocationSize
,
475 return UncachedInternalAllocateAlignedZeroPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
479 UncachedInternalAllocateAlignedCopyPool (
480 IN EFI_MEMORY_TYPE PoolType
,
481 IN UINTN AllocationSize
,
482 IN CONST VOID
*Buffer
,
488 ASSERT (Buffer
!= NULL
);
489 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
491 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
492 if (Memory
!= NULL
) {
493 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
500 UncachedAllocateAlignedCopyPool (
501 IN UINTN AllocationSize
,
502 IN CONST VOID
*Buffer
,
506 return UncachedInternalAllocateAlignedCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
, Alignment
);
511 UncachedAllocateAlignedRuntimeCopyPool (
512 IN UINTN AllocationSize
,
513 IN CONST VOID
*Buffer
,
517 return UncachedInternalAllocateAlignedCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
, Alignment
);
522 UncachedAllocateAlignedReservedCopyPool (
523 IN UINTN AllocationSize
,
524 IN CONST VOID
*Buffer
,
528 return UncachedInternalAllocateAlignedCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
, Alignment
);
533 UncachedFreeAlignedPool (
537 UncachedFreePages (Allocation
, 0);
541 UncachedInternalAllocatePool (
542 IN EFI_MEMORY_TYPE MemoryType
,
543 IN UINTN AllocationSize
546 UINTN CacheLineLength
= ArmDataCacheLineLength ();
547 return UncachedInternalAllocateAlignedPool (MemoryType
, AllocationSize
, CacheLineLength
);
552 UncachedAllocatePool (
553 IN UINTN AllocationSize
556 return UncachedInternalAllocatePool (EfiBootServicesData
, AllocationSize
);
561 UncachedAllocateRuntimePool (
562 IN UINTN AllocationSize
565 return UncachedInternalAllocatePool (EfiRuntimeServicesData
, AllocationSize
);
570 UncachedAllocateReservedPool (
571 IN UINTN AllocationSize
574 return UncachedInternalAllocatePool (EfiReservedMemoryType
, AllocationSize
);
578 UncachedInternalAllocateZeroPool (
579 IN EFI_MEMORY_TYPE PoolType
,
580 IN UINTN AllocationSize
585 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
586 if (Memory
!= NULL
) {
587 Memory
= ZeroMem (Memory
, AllocationSize
);
594 UncachedAllocateZeroPool (
595 IN UINTN AllocationSize
598 return UncachedInternalAllocateZeroPool (EfiBootServicesData
, AllocationSize
);
603 UncachedAllocateRuntimeZeroPool (
604 IN UINTN AllocationSize
607 return UncachedInternalAllocateZeroPool (EfiRuntimeServicesData
, AllocationSize
);
612 UncachedAllocateReservedZeroPool (
613 IN UINTN AllocationSize
616 return UncachedInternalAllocateZeroPool (EfiReservedMemoryType
, AllocationSize
);
620 UncachedInternalAllocateCopyPool (
621 IN EFI_MEMORY_TYPE PoolType
,
622 IN UINTN AllocationSize
,
623 IN CONST VOID
*Buffer
628 ASSERT (Buffer
!= NULL
);
629 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
631 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
632 if (Memory
!= NULL
) {
633 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
640 UncachedAllocateCopyPool (
641 IN UINTN AllocationSize
,
642 IN CONST VOID
*Buffer
645 return UncachedInternalAllocateCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
);
650 UncachedAllocateRuntimeCopyPool (
651 IN UINTN AllocationSize
,
652 IN CONST VOID
*Buffer
655 return UncachedInternalAllocateCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
);
660 UncachedAllocateReservedCopyPool (
661 IN UINTN AllocationSize
,
662 IN CONST VOID
*Buffer
665 return UncachedInternalAllocateCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
);
674 UncachedFreeAlignedPool (Buffer
);
679 UncachedSafeFreePool (
683 if (Buffer
!= NULL
) {
684 UncachedFreePool (Buffer
);