2 Debug version of the UncachedMemoryAllocation lib that uses the VirtualUncachedPages
3 protocol, produced by the DXE CPU driver, to produce debuggable uncached memory buffers.
5 The DMA rules for EFI contain the concept of a PCI (DMA master) address for memory and
6 a CPU (C code) address for the memory buffer that don't have to be the same. There seem to
7 be common errors out there with folks mixing up the two addresses. This library causes
8 the PCI (DMA master) address to not be mapped into system memory so if the CPU (C code)
9 uses the wrong pointer it will generate a page fault. The CPU (C code) version of the buffer
10 has a virtual address that does not match the physical address. The virtual address has
11 PcdArmUncachedMemoryMask ored into the physical address.
13 Copyright (c) 2008-2010, Apple Inc. All rights reserved.
15 All rights reserved. This program and the accompanying materials
16 are licensed and made available under the terms and conditions of the BSD License
17 which accompanies this distribution. The full text of the license may be found at
18 http://opensource.org/licenses/bsd-license.php
20 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
21 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
25 #include <Library/BaseLib.h>
26 #include <Library/BaseMemoryLib.h>
27 #include <Library/MemoryAllocationLib.h>
28 #include <Library/DebugLib.h>
29 #include <Library/UefiBootServicesTableLib.h>
30 #include <Library/UncachedMemoryAllocationLib.h>
31 #include <Library/PcdLib.h>
32 #include <Library/ArmLib.h>
34 #include <Protocol/Cpu.h>
35 #include <Protocol/VirtualUncachedPages.h>
38 UncachedInternalAllocatePages (
39 IN EFI_MEMORY_TYPE MemoryType
,
44 UncachedInternalAllocateAlignedPages (
45 IN EFI_MEMORY_TYPE MemoryType
,
52 EFI_CPU_ARCH_PROTOCOL
*gDebugUncachedCpu
;
53 VIRTUAL_UNCACHED_PAGES_PROTOCOL
*gVirtualUncachedPages
;
56 // Assume all of memory has the same cache attributes, unless we do our magic
67 LIST_ENTRY mPageList
= INITIALIZE_LIST_HEAD_VARIABLE (mPageList
);
76 FREE_PAGE_NODE
*NewNode
;
78 NewNode
= AllocatePool (sizeof (LIST_ENTRY
));
79 if (NewNode
== NULL
) {
84 NewNode
->Buffer
= Buffer
;
85 NewNode
->Allocation
= Allocation
;
87 InsertTailList (&mPageList
, &NewNode
->Link
);
94 OUT VOID
**Allocation
,
99 FREE_PAGE_NODE
*OldNode
;
104 for (Link
= mPageList
.ForwardLink
; Link
!= &mPageList
; Link
= Link
->ForwardLink
) {
105 OldNode
= BASE_CR (Link
, FREE_PAGE_NODE
, Link
);
106 if (OldNode
->Buffer
== Buffer
) {
107 *Allocation
= OldNode
->Allocation
;
108 *Pages
= OldNode
->Pages
;
110 RemoveEntryList (&OldNode
->Link
);
122 ConvertToPhysicalAddress (
123 IN VOID
*VirtualAddress
126 UINTN UncachedMemoryMask
= (UINTN
)PcdGet64 (PcdArmUncachedMemoryMask
);
127 UINTN PhysicalAddress
;
129 PhysicalAddress
= (UINTN
)VirtualAddress
& ~UncachedMemoryMask
;
131 return (EFI_PHYSICAL_ADDRESS
)PhysicalAddress
;
136 ConvertToUncachedAddress (
140 UINTN UncachedMemoryMask
= (UINTN
)PcdGet64 (PcdArmUncachedMemoryMask
);
141 UINTN UncachedAddress
;
143 UncachedAddress
= (UINTN
)Address
| UncachedMemoryMask
;
145 return (VOID
*)UncachedAddress
;
151 UncachedInternalAllocatePages (
152 IN EFI_MEMORY_TYPE MemoryType
,
156 return UncachedInternalAllocateAlignedPages (MemoryType
, Pages
, EFI_PAGE_SIZE
);
162 UncachedAllocatePages (
166 return UncachedInternalAllocatePages (EfiBootServicesData
, Pages
);
171 UncachedAllocateRuntimePages (
175 return UncachedInternalAllocatePages (EfiRuntimeServicesData
, Pages
);
180 UncachedAllocateReservedPages (
184 return UncachedInternalAllocatePages (EfiReservedMemoryType
, Pages
);
196 UncachedFreeAlignedPages (Buffer
, Pages
);
202 UncachedInternalAllocateAlignedPages (
203 IN EFI_MEMORY_TYPE MemoryType
,
209 EFI_PHYSICAL_ADDRESS Memory
;
210 EFI_PHYSICAL_ADDRESS AlignedMemory
;
212 UINTN UnalignedPages
;
216 // Alignment must be a power of two or zero.
218 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
223 if (Alignment
> EFI_PAGE_SIZE
) {
225 // Caculate the total number of pages since alignment is larger than page size.
227 AlignmentMask
= Alignment
- 1;
228 RealPages
= Pages
+ EFI_SIZE_TO_PAGES (Alignment
);
230 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
232 ASSERT (RealPages
> Pages
);
234 Status
= gBS
->AllocatePages (AllocateAnyPages
, MemoryType
, RealPages
, &Memory
);
235 if (EFI_ERROR (Status
)) {
238 AlignedMemory
= ((UINTN
) Memory
+ AlignmentMask
) & ~AlignmentMask
;
239 UnalignedPages
= EFI_SIZE_TO_PAGES (AlignedMemory
- (UINTN
) Memory
);
240 if (UnalignedPages
> 0) {
242 // Free first unaligned page(s).
244 Status
= gBS
->FreePages (Memory
, UnalignedPages
);
245 ASSERT_EFI_ERROR (Status
);
247 Memory
= (EFI_PHYSICAL_ADDRESS
) (AlignedMemory
+ EFI_PAGES_TO_SIZE (Pages
));
248 UnalignedPages
= RealPages
- Pages
- UnalignedPages
;
249 if (UnalignedPages
> 0) {
251 // Free last unaligned page(s).
253 Status
= gBS
->FreePages (Memory
, UnalignedPages
);
254 ASSERT_EFI_ERROR (Status
);
258 // Do not over-allocate pages in this case.
260 Status
= gBS
->AllocatePages (AllocateAnyPages
, MemoryType
, Pages
, &Memory
);
261 if (EFI_ERROR (Status
)) {
264 AlignedMemory
= (UINTN
) Memory
;
267 Status
= gVirtualUncachedPages
->ConvertPages (gVirtualUncachedPages
, AlignedMemory
, Pages
* EFI_PAGE_SIZE
, PcdGet64 (PcdArmUncachedMemoryMask
), &gAttributes
);
268 if (EFI_ERROR (Status
)) {
272 AlignedMemory
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)ConvertToUncachedAddress ((VOID
*)(UINTN
)AlignedMemory
);
274 return (VOID
*)(UINTN
)AlignedMemory
;
280 UncachedFreeAlignedPages (
286 EFI_PHYSICAL_ADDRESS Memory
;
290 Memory
= ConvertToPhysicalAddress (Buffer
);
292 Status
= gVirtualUncachedPages
->RevertPages (gVirtualUncachedPages
, Memory
, Pages
* EFI_PAGE_SIZE
, PcdGet64 (PcdArmUncachedMemoryMask
), gAttributes
);
295 Status
= gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Memory
, Pages
);
296 ASSERT_EFI_ERROR (Status
);
303 UncachedInternalAllocateAlignedPool (
304 IN EFI_MEMORY_TYPE PoolType
,
305 IN UINTN AllocationSize
,
309 VOID
*AlignedAddress
;
312 // Alignment must be a power of two or zero.
314 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
316 if (Alignment
< EFI_PAGE_SIZE
) {
317 Alignment
= EFI_PAGE_SIZE
;
320 AlignedAddress
= UncachedInternalAllocateAlignedPages (PoolType
, EFI_SIZE_TO_PAGES (AllocationSize
), Alignment
);
321 if (AlignedAddress
== NULL
) {
325 AddPagesToList ((VOID
*)(UINTN
)ConvertToPhysicalAddress (AlignedAddress
), (VOID
*)(UINTN
)AlignedAddress
, EFI_SIZE_TO_PAGES (AllocationSize
));
327 return (VOID
*) AlignedAddress
;
332 UncachedAllocateAlignedPool (
333 IN UINTN AllocationSize
,
337 return UncachedInternalAllocateAlignedPool (EfiBootServicesData
, AllocationSize
, Alignment
);
342 UncachedAllocateAlignedRuntimePool (
343 IN UINTN AllocationSize
,
347 return UncachedInternalAllocateAlignedPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
352 UncachedAllocateAlignedReservedPool (
353 IN UINTN AllocationSize
,
357 return UncachedInternalAllocateAlignedPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
361 UncachedInternalAllocateAlignedZeroPool (
362 IN EFI_MEMORY_TYPE PoolType
,
363 IN UINTN AllocationSize
,
368 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
369 if (Memory
!= NULL
) {
370 Memory
= ZeroMem (Memory
, AllocationSize
);
377 UncachedAllocateAlignedZeroPool (
378 IN UINTN AllocationSize
,
382 return UncachedInternalAllocateAlignedZeroPool (EfiBootServicesData
, AllocationSize
, Alignment
);
387 UncachedAllocateAlignedRuntimeZeroPool (
388 IN UINTN AllocationSize
,
392 return UncachedInternalAllocateAlignedZeroPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
397 UncachedAllocateAlignedReservedZeroPool (
398 IN UINTN AllocationSize
,
402 return UncachedInternalAllocateAlignedZeroPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
406 UncachedInternalAllocateAlignedCopyPool (
407 IN EFI_MEMORY_TYPE PoolType
,
408 IN UINTN AllocationSize
,
409 IN CONST VOID
*Buffer
,
415 ASSERT (Buffer
!= NULL
);
416 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
418 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
419 if (Memory
!= NULL
) {
420 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
427 UncachedAllocateAlignedCopyPool (
428 IN UINTN AllocationSize
,
429 IN CONST VOID
*Buffer
,
433 return UncachedInternalAllocateAlignedCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
, Alignment
);
438 UncachedAllocateAlignedRuntimeCopyPool (
439 IN UINTN AllocationSize
,
440 IN CONST VOID
*Buffer
,
444 return UncachedInternalAllocateAlignedCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
, Alignment
);
449 UncachedAllocateAlignedReservedCopyPool (
450 IN UINTN AllocationSize
,
451 IN CONST VOID
*Buffer
,
455 return UncachedInternalAllocateAlignedCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
, Alignment
);
460 UncachedFreeAlignedPool (
467 RemovePagesFromList (Buffer
, &Allocation
, &Pages
);
469 UncachedFreePages (Allocation
, Pages
);
473 UncachedInternalAllocatePool (
474 IN EFI_MEMORY_TYPE MemoryType
,
475 IN UINTN AllocationSize
478 UINTN CacheLineLength
= ArmDataCacheLineLength ();
479 return UncachedInternalAllocateAlignedPool (MemoryType
, AllocationSize
, CacheLineLength
);
484 UncachedAllocatePool (
485 IN UINTN AllocationSize
488 return UncachedInternalAllocatePool (EfiBootServicesData
, AllocationSize
);
493 UncachedAllocateRuntimePool (
494 IN UINTN AllocationSize
497 return UncachedInternalAllocatePool (EfiRuntimeServicesData
, AllocationSize
);
502 UncachedAllocateReservedPool (
503 IN UINTN AllocationSize
506 return UncachedInternalAllocatePool (EfiReservedMemoryType
, AllocationSize
);
510 UncachedInternalAllocateZeroPool (
511 IN EFI_MEMORY_TYPE PoolType
,
512 IN UINTN AllocationSize
517 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
518 if (Memory
!= NULL
) {
519 Memory
= ZeroMem (Memory
, AllocationSize
);
526 UncachedAllocateZeroPool (
527 IN UINTN AllocationSize
530 return UncachedInternalAllocateZeroPool (EfiBootServicesData
, AllocationSize
);
535 UncachedAllocateRuntimeZeroPool (
536 IN UINTN AllocationSize
539 return UncachedInternalAllocateZeroPool (EfiRuntimeServicesData
, AllocationSize
);
544 UncachedAllocateReservedZeroPool (
545 IN UINTN AllocationSize
548 return UncachedInternalAllocateZeroPool (EfiReservedMemoryType
, AllocationSize
);
552 UncachedInternalAllocateCopyPool (
553 IN EFI_MEMORY_TYPE PoolType
,
554 IN UINTN AllocationSize
,
555 IN CONST VOID
*Buffer
560 ASSERT (Buffer
!= NULL
);
561 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
563 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
564 if (Memory
!= NULL
) {
565 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
572 UncachedAllocateCopyPool (
573 IN UINTN AllocationSize
,
574 IN CONST VOID
*Buffer
577 return UncachedInternalAllocateCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
);
582 UncachedAllocateRuntimeCopyPool (
583 IN UINTN AllocationSize
,
584 IN CONST VOID
*Buffer
587 return UncachedInternalAllocateCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
);
592 UncachedAllocateReservedCopyPool (
593 IN UINTN AllocationSize
,
594 IN CONST VOID
*Buffer
597 return UncachedInternalAllocateCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
);
606 UncachedFreeAlignedPool (Buffer
);
611 UncachedSafeFreePool (
615 if (Buffer
!= NULL
) {
616 UncachedFreePool (Buffer
);
622 The constructor function caches the pointer of DXE Services Table.
624 The constructor function caches the pointer of DXE Services Table.
625 It will ASSERT() if that operation fails.
626 It will ASSERT() if the pointer of DXE Services Table is NULL.
627 It will always return EFI_SUCCESS.
629 @param ImageHandle The firmware allocated handle for the EFI image.
630 @param SystemTable A pointer to the EFI System Table.
632 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
637 DebugUncachedMemoryAllocationLibConstructor (
638 IN EFI_HANDLE ImageHandle
,
639 IN EFI_SYSTEM_TABLE
*SystemTable
644 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**)&gDebugUncachedCpu
);
645 ASSERT_EFI_ERROR(Status
);
647 Status
= gBS
->LocateProtocol (&gVirtualUncachedPagesProtocolGuid
, NULL
, (VOID
**)&gVirtualUncachedPages
);
648 ASSERT_EFI_ERROR(Status
);