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.<BR>
15 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.
26 #include <Library/BaseLib.h>
27 #include <Library/BaseMemoryLib.h>
28 #include <Library/MemoryAllocationLib.h>
29 #include <Library/DebugLib.h>
30 #include <Library/UefiBootServicesTableLib.h>
31 #include <Library/UncachedMemoryAllocationLib.h>
32 #include <Library/PcdLib.h>
33 #include <Library/ArmLib.h>
35 #include <Protocol/Cpu.h>
36 #include <Protocol/VirtualUncachedPages.h>
39 UncachedInternalAllocatePages (
40 IN EFI_MEMORY_TYPE MemoryType
,
45 UncachedInternalAllocateAlignedPages (
46 IN EFI_MEMORY_TYPE MemoryType
,
53 EFI_CPU_ARCH_PROTOCOL
*gDebugUncachedCpu
;
54 VIRTUAL_UNCACHED_PAGES_PROTOCOL
*gVirtualUncachedPages
;
57 // Assume all of memory has the same cache attributes, unless we do our magic
68 LIST_ENTRY mPageList
= INITIALIZE_LIST_HEAD_VARIABLE (mPageList
);
77 FREE_PAGE_NODE
*NewNode
;
79 NewNode
= AllocatePool (sizeof (LIST_ENTRY
));
80 if (NewNode
== NULL
) {
85 NewNode
->Buffer
= Buffer
;
86 NewNode
->Allocation
= Allocation
;
87 NewNode
->Pages
= Pages
;
89 InsertTailList (&mPageList
, &NewNode
->Link
);
96 OUT VOID
**Allocation
,
101 FREE_PAGE_NODE
*OldNode
;
106 for (Link
= mPageList
.ForwardLink
; Link
!= &mPageList
; Link
= Link
->ForwardLink
) {
107 OldNode
= BASE_CR (Link
, FREE_PAGE_NODE
, Link
);
108 if (OldNode
->Buffer
== Buffer
) {
109 *Allocation
= OldNode
->Allocation
;
110 *Pages
= OldNode
->Pages
;
112 RemoveEntryList (&OldNode
->Link
);
124 ConvertToPhysicalAddress (
125 IN VOID
*VirtualAddress
128 UINTN UncachedMemoryMask
= (UINTN
)PcdGet64 (PcdArmUncachedMemoryMask
);
129 UINTN PhysicalAddress
;
131 PhysicalAddress
= (UINTN
)VirtualAddress
& ~UncachedMemoryMask
;
133 return (EFI_PHYSICAL_ADDRESS
)PhysicalAddress
;
138 ConvertToUncachedAddress (
142 UINTN UncachedMemoryMask
= (UINTN
)PcdGet64 (PcdArmUncachedMemoryMask
);
143 UINTN UncachedAddress
;
145 UncachedAddress
= (UINTN
)Address
| UncachedMemoryMask
;
147 return (VOID
*)UncachedAddress
;
153 UncachedInternalAllocatePages (
154 IN EFI_MEMORY_TYPE MemoryType
,
158 return UncachedInternalAllocateAlignedPages (MemoryType
, Pages
, EFI_PAGE_SIZE
);
164 UncachedAllocatePages (
168 return UncachedInternalAllocatePages (EfiBootServicesData
, Pages
);
173 UncachedAllocateRuntimePages (
177 return UncachedInternalAllocatePages (EfiRuntimeServicesData
, Pages
);
182 UncachedAllocateReservedPages (
186 return UncachedInternalAllocatePages (EfiReservedMemoryType
, Pages
);
198 UncachedFreeAlignedPages (Buffer
, Pages
);
204 UncachedInternalAllocateAlignedPages (
205 IN EFI_MEMORY_TYPE MemoryType
,
211 EFI_PHYSICAL_ADDRESS Memory
;
212 EFI_PHYSICAL_ADDRESS AlignedMemory
;
214 UINTN UnalignedPages
;
218 // Alignment must be a power of two or zero.
220 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
225 if (Alignment
> EFI_PAGE_SIZE
) {
227 // Caculate the total number of pages since alignment is larger than page size.
229 AlignmentMask
= Alignment
- 1;
230 RealPages
= Pages
+ EFI_SIZE_TO_PAGES (Alignment
);
232 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
234 ASSERT (RealPages
> Pages
);
236 Status
= gBS
->AllocatePages (AllocateAnyPages
, MemoryType
, RealPages
, &Memory
);
237 if (EFI_ERROR (Status
)) {
240 AlignedMemory
= ((UINTN
) Memory
+ AlignmentMask
) & ~AlignmentMask
;
241 UnalignedPages
= EFI_SIZE_TO_PAGES (AlignedMemory
- (UINTN
) Memory
);
242 if (UnalignedPages
> 0) {
244 // Free first unaligned page(s).
246 Status
= gBS
->FreePages (Memory
, UnalignedPages
);
247 ASSERT_EFI_ERROR (Status
);
249 Memory
= (EFI_PHYSICAL_ADDRESS
) (AlignedMemory
+ EFI_PAGES_TO_SIZE (Pages
));
250 UnalignedPages
= RealPages
- Pages
- UnalignedPages
;
251 if (UnalignedPages
> 0) {
253 // Free last unaligned page(s).
255 Status
= gBS
->FreePages (Memory
, UnalignedPages
);
256 ASSERT_EFI_ERROR (Status
);
260 // Do not over-allocate pages in this case.
262 Status
= gBS
->AllocatePages (AllocateAnyPages
, MemoryType
, Pages
, &Memory
);
263 if (EFI_ERROR (Status
)) {
266 AlignedMemory
= (UINTN
) Memory
;
269 Status
= gVirtualUncachedPages
->ConvertPages (gVirtualUncachedPages
, AlignedMemory
, Pages
* EFI_PAGE_SIZE
, PcdGet64 (PcdArmUncachedMemoryMask
), &gAttributes
);
270 if (EFI_ERROR (Status
)) {
274 AlignedMemory
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)ConvertToUncachedAddress ((VOID
*)(UINTN
)AlignedMemory
);
276 return (VOID
*)(UINTN
)AlignedMemory
;
282 UncachedFreeAlignedPages (
288 EFI_PHYSICAL_ADDRESS Memory
;
292 Memory
= ConvertToPhysicalAddress (Buffer
);
294 Status
= gVirtualUncachedPages
->RevertPages (gVirtualUncachedPages
, Memory
, Pages
* EFI_PAGE_SIZE
, PcdGet64 (PcdArmUncachedMemoryMask
), gAttributes
);
297 Status
= gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Memory
, Pages
);
298 ASSERT_EFI_ERROR (Status
);
305 UncachedInternalAllocateAlignedPool (
306 IN EFI_MEMORY_TYPE PoolType
,
307 IN UINTN AllocationSize
,
311 VOID
*AlignedAddress
;
314 // Alignment must be a power of two or zero.
316 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
318 if (Alignment
< EFI_PAGE_SIZE
) {
319 Alignment
= EFI_PAGE_SIZE
;
322 AlignedAddress
= UncachedInternalAllocateAlignedPages (PoolType
, EFI_SIZE_TO_PAGES (AllocationSize
), Alignment
);
323 if (AlignedAddress
== NULL
) {
327 AddPagesToList ((VOID
*)(UINTN
)ConvertToPhysicalAddress (AlignedAddress
), (VOID
*)(UINTN
)AlignedAddress
, EFI_SIZE_TO_PAGES (AllocationSize
));
329 return (VOID
*) AlignedAddress
;
334 UncachedAllocateAlignedPool (
335 IN UINTN AllocationSize
,
339 return UncachedInternalAllocateAlignedPool (EfiBootServicesData
, AllocationSize
, Alignment
);
344 UncachedAllocateAlignedRuntimePool (
345 IN UINTN AllocationSize
,
349 return UncachedInternalAllocateAlignedPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
354 UncachedAllocateAlignedReservedPool (
355 IN UINTN AllocationSize
,
359 return UncachedInternalAllocateAlignedPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
363 UncachedInternalAllocateAlignedZeroPool (
364 IN EFI_MEMORY_TYPE PoolType
,
365 IN UINTN AllocationSize
,
370 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
371 if (Memory
!= NULL
) {
372 Memory
= ZeroMem (Memory
, AllocationSize
);
379 UncachedAllocateAlignedZeroPool (
380 IN UINTN AllocationSize
,
384 return UncachedInternalAllocateAlignedZeroPool (EfiBootServicesData
, AllocationSize
, Alignment
);
389 UncachedAllocateAlignedRuntimeZeroPool (
390 IN UINTN AllocationSize
,
394 return UncachedInternalAllocateAlignedZeroPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
399 UncachedAllocateAlignedReservedZeroPool (
400 IN UINTN AllocationSize
,
404 return UncachedInternalAllocateAlignedZeroPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
408 UncachedInternalAllocateAlignedCopyPool (
409 IN EFI_MEMORY_TYPE PoolType
,
410 IN UINTN AllocationSize
,
411 IN CONST VOID
*Buffer
,
417 ASSERT (Buffer
!= NULL
);
418 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
420 Memory
= UncachedInternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
421 if (Memory
!= NULL
) {
422 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
429 UncachedAllocateAlignedCopyPool (
430 IN UINTN AllocationSize
,
431 IN CONST VOID
*Buffer
,
435 return UncachedInternalAllocateAlignedCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
, Alignment
);
440 UncachedAllocateAlignedRuntimeCopyPool (
441 IN UINTN AllocationSize
,
442 IN CONST VOID
*Buffer
,
446 return UncachedInternalAllocateAlignedCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
, Alignment
);
451 UncachedAllocateAlignedReservedCopyPool (
452 IN UINTN AllocationSize
,
453 IN CONST VOID
*Buffer
,
457 return UncachedInternalAllocateAlignedCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
, Alignment
);
462 UncachedFreeAlignedPool (
469 RemovePagesFromList (Buffer
, &Allocation
, &Pages
);
471 UncachedFreePages (Allocation
, Pages
);
475 UncachedInternalAllocatePool (
476 IN EFI_MEMORY_TYPE MemoryType
,
477 IN UINTN AllocationSize
480 UINTN CacheLineLength
= ArmDataCacheLineLength ();
481 return UncachedInternalAllocateAlignedPool (MemoryType
, AllocationSize
, CacheLineLength
);
486 UncachedAllocatePool (
487 IN UINTN AllocationSize
490 return UncachedInternalAllocatePool (EfiBootServicesData
, AllocationSize
);
495 UncachedAllocateRuntimePool (
496 IN UINTN AllocationSize
499 return UncachedInternalAllocatePool (EfiRuntimeServicesData
, AllocationSize
);
504 UncachedAllocateReservedPool (
505 IN UINTN AllocationSize
508 return UncachedInternalAllocatePool (EfiReservedMemoryType
, AllocationSize
);
512 UncachedInternalAllocateZeroPool (
513 IN EFI_MEMORY_TYPE PoolType
,
514 IN UINTN AllocationSize
519 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
520 if (Memory
!= NULL
) {
521 Memory
= ZeroMem (Memory
, AllocationSize
);
528 UncachedAllocateZeroPool (
529 IN UINTN AllocationSize
532 return UncachedInternalAllocateZeroPool (EfiBootServicesData
, AllocationSize
);
537 UncachedAllocateRuntimeZeroPool (
538 IN UINTN AllocationSize
541 return UncachedInternalAllocateZeroPool (EfiRuntimeServicesData
, AllocationSize
);
546 UncachedAllocateReservedZeroPool (
547 IN UINTN AllocationSize
550 return UncachedInternalAllocateZeroPool (EfiReservedMemoryType
, AllocationSize
);
554 UncachedInternalAllocateCopyPool (
555 IN EFI_MEMORY_TYPE PoolType
,
556 IN UINTN AllocationSize
,
557 IN CONST VOID
*Buffer
562 ASSERT (Buffer
!= NULL
);
563 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
565 Memory
= UncachedInternalAllocatePool (PoolType
, AllocationSize
);
566 if (Memory
!= NULL
) {
567 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
574 UncachedAllocateCopyPool (
575 IN UINTN AllocationSize
,
576 IN CONST VOID
*Buffer
579 return UncachedInternalAllocateCopyPool (EfiBootServicesData
, AllocationSize
, Buffer
);
584 UncachedAllocateRuntimeCopyPool (
585 IN UINTN AllocationSize
,
586 IN CONST VOID
*Buffer
589 return UncachedInternalAllocateCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
);
594 UncachedAllocateReservedCopyPool (
595 IN UINTN AllocationSize
,
596 IN CONST VOID
*Buffer
599 return UncachedInternalAllocateCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
);
608 UncachedFreeAlignedPool (Buffer
);
613 UncachedSafeFreePool (
617 if (Buffer
!= NULL
) {
618 UncachedFreePool (Buffer
);
624 The constructor function caches the pointer of DXE Services Table.
626 The constructor function caches the pointer of DXE Services Table.
627 It will ASSERT() if that operation fails.
628 It will ASSERT() if the pointer of DXE Services Table is NULL.
629 It will always return EFI_SUCCESS.
631 @param ImageHandle The firmware allocated handle for the EFI image.
632 @param SystemTable A pointer to the EFI System Table.
634 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
639 DebugUncachedMemoryAllocationLibConstructor (
640 IN EFI_HANDLE ImageHandle
,
641 IN EFI_SYSTEM_TABLE
*SystemTable
646 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**)&gDebugUncachedCpu
);
647 ASSERT_EFI_ERROR(Status
);
649 Status
= gBS
->LocateProtocol (&gVirtualUncachedPagesProtocolGuid
, NULL
, (VOID
**)&gVirtualUncachedPages
);
650 ASSERT_EFI_ERROR(Status
);