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
;
86 NewNode
->Pages
= Pages
;
88 InsertTailList (&mPageList
, &NewNode
->Link
);
95 OUT VOID
**Allocation
,
100 FREE_PAGE_NODE
*OldNode
;
105 for (Link
= mPageList
.ForwardLink
; Link
!= &mPageList
; Link
= Link
->ForwardLink
) {
106 OldNode
= BASE_CR (Link
, FREE_PAGE_NODE
, Link
);
107 if (OldNode
->Buffer
== Buffer
) {
108 *Allocation
= OldNode
->Allocation
;
109 *Pages
= OldNode
->Pages
;
111 RemoveEntryList (&OldNode
->Link
);
123 ConvertToPhysicalAddress (
124 IN VOID
*VirtualAddress
127 UINTN UncachedMemoryMask
= (UINTN
)PcdGet64 (PcdArmUncachedMemoryMask
);
128 UINTN PhysicalAddress
;
130 PhysicalAddress
= (UINTN
)VirtualAddress
& ~UncachedMemoryMask
;
132 return (EFI_PHYSICAL_ADDRESS
)PhysicalAddress
;
137 ConvertToUncachedAddress (
141 UINTN UncachedMemoryMask
= (UINTN
)PcdGet64 (PcdArmUncachedMemoryMask
);
142 UINTN UncachedAddress
;
144 UncachedAddress
= (UINTN
)Address
| UncachedMemoryMask
;
146 return (VOID
*)UncachedAddress
;
152 UncachedInternalAllocatePages (
153 IN EFI_MEMORY_TYPE MemoryType
,
157 return UncachedInternalAllocateAlignedPages (MemoryType
, Pages
, EFI_PAGE_SIZE
);
163 UncachedAllocatePages (
167 return UncachedInternalAllocatePages (EfiBootServicesData
, Pages
);
172 UncachedAllocateRuntimePages (
176 return UncachedInternalAllocatePages (EfiRuntimeServicesData
, Pages
);
181 UncachedAllocateReservedPages (
185 return UncachedInternalAllocatePages (EfiReservedMemoryType
, Pages
);
197 UncachedFreeAlignedPages (Buffer
, Pages
);
203 UncachedInternalAllocateAlignedPages (
204 IN EFI_MEMORY_TYPE MemoryType
,
210 EFI_PHYSICAL_ADDRESS Memory
;
211 EFI_PHYSICAL_ADDRESS AlignedMemory
;
213 UINTN UnalignedPages
;
217 // Alignment must be a power of two or zero.
219 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
224 if (Alignment
> EFI_PAGE_SIZE
) {
226 // Caculate the total number of pages since alignment is larger than page size.
228 AlignmentMask
= Alignment
- 1;
229 RealPages
= Pages
+ EFI_SIZE_TO_PAGES (Alignment
);
231 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
233 ASSERT (RealPages
> Pages
);
235 Status
= gBS
->AllocatePages (AllocateAnyPages
, MemoryType
, RealPages
, &Memory
);
236 if (EFI_ERROR (Status
)) {
239 AlignedMemory
= ((UINTN
) Memory
+ AlignmentMask
) & ~AlignmentMask
;
240 UnalignedPages
= EFI_SIZE_TO_PAGES (AlignedMemory
- (UINTN
) Memory
);
241 if (UnalignedPages
> 0) {
243 // Free first unaligned page(s).
245 Status
= gBS
->FreePages (Memory
, UnalignedPages
);
246 ASSERT_EFI_ERROR (Status
);
248 Memory
= (EFI_PHYSICAL_ADDRESS
) (AlignedMemory
+ EFI_PAGES_TO_SIZE (Pages
));
249 UnalignedPages
= RealPages
- Pages
- UnalignedPages
;
250 if (UnalignedPages
> 0) {
252 // Free last unaligned page(s).
254 Status
= gBS
->FreePages (Memory
, UnalignedPages
);
255 ASSERT_EFI_ERROR (Status
);
259 // Do not over-allocate pages in this case.
261 Status
= gBS
->AllocatePages (AllocateAnyPages
, MemoryType
, Pages
, &Memory
);
262 if (EFI_ERROR (Status
)) {
265 AlignedMemory
= (UINTN
) Memory
;
268 Status
= gVirtualUncachedPages
->ConvertPages (gVirtualUncachedPages
, AlignedMemory
, Pages
* EFI_PAGE_SIZE
, PcdGet64 (PcdArmUncachedMemoryMask
), &gAttributes
);
269 if (EFI_ERROR (Status
)) {
273 AlignedMemory
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)ConvertToUncachedAddress ((VOID
*)(UINTN
)AlignedMemory
);
275 return (VOID
*)(UINTN
)AlignedMemory
;
281 UncachedFreeAlignedPages (
287 EFI_PHYSICAL_ADDRESS Memory
;
291 Memory
= ConvertToPhysicalAddress (Buffer
);
293 Status
= gVirtualUncachedPages
->RevertPages (gVirtualUncachedPages
, Memory
, Pages
* EFI_PAGE_SIZE
, PcdGet64 (PcdArmUncachedMemoryMask
), gAttributes
);
296 Status
= gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Memory
, Pages
);
297 ASSERT_EFI_ERROR (Status
);
304 UncachedInternalAllocateAlignedPool (
305 IN EFI_MEMORY_TYPE PoolType
,
306 IN UINTN AllocationSize
,
310 VOID
*AlignedAddress
;
313 // Alignment must be a power of two or zero.
315 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
317 if (Alignment
< EFI_PAGE_SIZE
) {
318 Alignment
= EFI_PAGE_SIZE
;
321 AlignedAddress
= UncachedInternalAllocateAlignedPages (PoolType
, EFI_SIZE_TO_PAGES (AllocationSize
), Alignment
);
322 if (AlignedAddress
== NULL
) {
326 AddPagesToList ((VOID
*)(UINTN
)ConvertToPhysicalAddress (AlignedAddress
), (VOID
*)(UINTN
)AlignedAddress
, EFI_SIZE_TO_PAGES (AllocationSize
));
328 return (VOID
*) AlignedAddress
;
333 UncachedAllocateAlignedPool (
334 IN UINTN AllocationSize
,
338 return UncachedInternalAllocateAlignedPool (EfiBootServicesData
, AllocationSize
, Alignment
);
343 UncachedAllocateAlignedRuntimePool (
344 IN UINTN AllocationSize
,
348 return UncachedInternalAllocateAlignedPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
353 UncachedAllocateAlignedReservedPool (
354 IN UINTN AllocationSize
,
358 return UncachedInternalAllocateAlignedPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
362 UncachedInternalAllocateAlignedZeroPool (
363 IN EFI_MEMORY_TYPE PoolType
,
364 IN UINTN AllocationSize
,
369 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
370 if (Memory
!= NULL
) {
371 Memory
= ZeroMem (Memory
, AllocationSize
);
378 UncachedAllocateAlignedZeroPool (
379 IN UINTN AllocationSize
,
383 return UncachedInternalAllocateAlignedZeroPool (EfiBootServicesData
, AllocationSize
, Alignment
);
388 UncachedAllocateAlignedRuntimeZeroPool (
389 IN UINTN AllocationSize
,
393 return UncachedInternalAllocateAlignedZeroPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
398 UncachedAllocateAlignedReservedZeroPool (
399 IN UINTN AllocationSize
,
403 return UncachedInternalAllocateAlignedZeroPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
407 UncachedInternalAllocateAlignedCopyPool (
408 IN EFI_MEMORY_TYPE PoolType
,
409 IN UINTN AllocationSize
,
410 IN CONST VOID
*Buffer
,
416 ASSERT (Buffer
!= NULL
);
417 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
419 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
420 if (Memory
!= NULL
) {
421 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
428 UncachedAllocateAlignedCopyPool (
429 IN UINTN AllocationSize
,
430 IN CONST VOID
*Buffer
,
434 return UncachedInternalAllocateAlignedCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
, Alignment
);
439 UncachedAllocateAlignedRuntimeCopyPool (
440 IN UINTN AllocationSize
,
441 IN CONST VOID
*Buffer
,
445 return UncachedInternalAllocateAlignedCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
, Alignment
);
450 UncachedAllocateAlignedReservedCopyPool (
451 IN UINTN AllocationSize
,
452 IN CONST VOID
*Buffer
,
456 return UncachedInternalAllocateAlignedCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
, Alignment
);
461 UncachedFreeAlignedPool (
468 RemovePagesFromList (Buffer
, &Allocation
, &Pages
);
470 UncachedFreePages (Allocation
, Pages
);
474 UncachedInternalAllocatePool (
475 IN EFI_MEMORY_TYPE MemoryType
,
476 IN UINTN AllocationSize
479 UINTN CacheLineLength
= ArmDataCacheLineLength ();
480 return UncachedInternalAllocateAlignedPool (MemoryType
, AllocationSize
, CacheLineLength
);
485 UncachedAllocatePool (
486 IN UINTN AllocationSize
489 return UncachedInternalAllocatePool (EfiBootServicesData
, AllocationSize
);
494 UncachedAllocateRuntimePool (
495 IN UINTN AllocationSize
498 return UncachedInternalAllocatePool (EfiRuntimeServicesData
, AllocationSize
);
503 UncachedAllocateReservedPool (
504 IN UINTN AllocationSize
507 return UncachedInternalAllocatePool (EfiReservedMemoryType
, AllocationSize
);
511 UncachedInternalAllocateZeroPool (
512 IN EFI_MEMORY_TYPE PoolType
,
513 IN UINTN AllocationSize
518 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
519 if (Memory
!= NULL
) {
520 Memory
= ZeroMem (Memory
, AllocationSize
);
527 UncachedAllocateZeroPool (
528 IN UINTN AllocationSize
531 return UncachedInternalAllocateZeroPool (EfiBootServicesData
, AllocationSize
);
536 UncachedAllocateRuntimeZeroPool (
537 IN UINTN AllocationSize
540 return UncachedInternalAllocateZeroPool (EfiRuntimeServicesData
, AllocationSize
);
545 UncachedAllocateReservedZeroPool (
546 IN UINTN AllocationSize
549 return UncachedInternalAllocateZeroPool (EfiReservedMemoryType
, AllocationSize
);
553 UncachedInternalAllocateCopyPool (
554 IN EFI_MEMORY_TYPE PoolType
,
555 IN UINTN AllocationSize
,
556 IN CONST VOID
*Buffer
561 ASSERT (Buffer
!= NULL
);
562 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
564 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
565 if (Memory
!= NULL
) {
566 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
573 UncachedAllocateCopyPool (
574 IN UINTN AllocationSize
,
575 IN CONST VOID
*Buffer
578 return UncachedInternalAllocateCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
);
583 UncachedAllocateRuntimeCopyPool (
584 IN UINTN AllocationSize
,
585 IN CONST VOID
*Buffer
588 return UncachedInternalAllocateCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
);
593 UncachedAllocateReservedCopyPool (
594 IN UINTN AllocationSize
,
595 IN CONST VOID
*Buffer
598 return UncachedInternalAllocateCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
);
607 UncachedFreeAlignedPool (Buffer
);
612 UncachedSafeFreePool (
616 if (Buffer
!= NULL
) {
617 UncachedFreePool (Buffer
);
623 The constructor function caches the pointer of DXE Services Table.
625 The constructor function caches the pointer of DXE Services Table.
626 It will ASSERT() if that operation fails.
627 It will ASSERT() if the pointer of DXE Services Table is NULL.
628 It will always return EFI_SUCCESS.
630 @param ImageHandle The firmware allocated handle for the EFI image.
631 @param SystemTable A pointer to the EFI System Table.
633 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
638 DebugUncachedMemoryAllocationLibConstructor (
639 IN EFI_HANDLE ImageHandle
,
640 IN EFI_SYSTEM_TABLE
*SystemTable
645 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**)&gDebugUncachedCpu
);
646 ASSERT_EFI_ERROR(Status
);
648 Status
= gBS
->LocateProtocol (&gVirtualUncachedPagesProtocolGuid
, NULL
, (VOID
**)&gVirtualUncachedPages
);
649 ASSERT_EFI_ERROR(Status
);