+++ /dev/null
-/** @file\r
- Debug version of the UncachedMemoryAllocation lib that uses the VirtualUncachedPages\r
- protocol, produced by the DXE CPU driver, to produce debuggable uncached memory buffers.\r
-\r
- The DMA rules for EFI contain the concept of a PCI (DMA master) address for memory and\r
- a CPU (C code) address for the memory buffer that don't have to be the same. There seem to\r
- be common errors out there with folks mixing up the two addresses. This library causes\r
- the PCI (DMA master) address to not be mapped into system memory so if the CPU (C code)\r
- uses the wrong pointer it will generate a page fault. The CPU (C code) version of the buffer\r
- has a virtual address that does not match the physical address. The virtual address has\r
- PcdArmUncachedMemoryMask ored into the physical address.\r
-\r
- Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
-\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-#include <Base.h>\r
-#include <Library/BaseLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/DebugLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-#include <Library/UncachedMemoryAllocationLib.h>\r
-#include <Library/PcdLib.h>\r
-#include <Library/ArmLib.h>\r
-\r
-#include <Protocol/Cpu.h>\r
-#include <Protocol/VirtualUncachedPages.h>\r
-\r
-VOID *\r
-UncachedInternalAllocatePages (\r
- IN EFI_MEMORY_TYPE MemoryType,\r
- IN UINTN Pages\r
- );\r
-\r
-VOID *\r
-UncachedInternalAllocateAlignedPages (\r
- IN EFI_MEMORY_TYPE MemoryType,\r
- IN UINTN Pages,\r
- IN UINTN Alignment\r
- );\r
-\r
-\r
-\r
-EFI_CPU_ARCH_PROTOCOL *gDebugUncachedCpu;\r
-VIRTUAL_UNCACHED_PAGES_PROTOCOL *gVirtualUncachedPages;\r
-\r
-//\r
-// Assume all of memory has the same cache attributes, unless we do our magic\r
-//\r
-UINT64 gAttributes;\r
-\r
-typedef struct {\r
- VOID *Buffer;\r
- VOID *Allocation;\r
- UINTN Pages;\r
- LIST_ENTRY Link;\r
-} FREE_PAGE_NODE;\r
-\r
-LIST_ENTRY mPageList = INITIALIZE_LIST_HEAD_VARIABLE (mPageList);\r
-\r
-VOID\r
-AddPagesToList (\r
- IN VOID *Buffer,\r
- IN VOID *Allocation,\r
- UINTN Pages\r
- )\r
-{\r
- FREE_PAGE_NODE *NewNode;\r
-\r
- NewNode = AllocatePool (sizeof (LIST_ENTRY));\r
- if (NewNode == NULL) {\r
- ASSERT (FALSE);\r
- return;\r
- }\r
-\r
- NewNode->Buffer = Buffer;\r
- NewNode->Allocation = Allocation;\r
- NewNode->Pages = Pages;\r
-\r
- InsertTailList (&mPageList, &NewNode->Link);\r
-}\r
-\r
-\r
-VOID\r
-RemovePagesFromList (\r
- IN VOID *Buffer,\r
- OUT VOID **Allocation,\r
- OUT UINTN *Pages\r
- )\r
-{\r
- LIST_ENTRY *Link;\r
- FREE_PAGE_NODE *OldNode;\r
-\r
- *Allocation = NULL;\r
- *Pages = 0;\r
-\r
- for (Link = mPageList.ForwardLink; Link != &mPageList; Link = Link->ForwardLink) {\r
- OldNode = BASE_CR (Link, FREE_PAGE_NODE, Link);\r
- if (OldNode->Buffer == Buffer) {\r
- *Allocation = OldNode->Allocation;\r
- *Pages = OldNode->Pages;\r
-\r
- RemoveEntryList (&OldNode->Link);\r
- FreePool (OldNode);\r
- return;\r
- }\r
- }\r
-\r
- return;\r
-}\r
-\r
-\r
-\r
-EFI_PHYSICAL_ADDRESS\r
-ConvertToPhysicalAddress (\r
- IN VOID *VirtualAddress\r
- )\r
-{\r
- UINTN UncachedMemoryMask = (UINTN)PcdGet64 (PcdArmUncachedMemoryMask);\r
- UINTN PhysicalAddress;\r
-\r
- PhysicalAddress = (UINTN)VirtualAddress & ~UncachedMemoryMask;\r
-\r
- return (EFI_PHYSICAL_ADDRESS)PhysicalAddress;\r
-}\r
-\r
-\r
-VOID *\r
-ConvertToUncachedAddress (\r
- IN VOID *Address\r
- )\r
-{\r
- UINTN UncachedMemoryMask = (UINTN)PcdGet64 (PcdArmUncachedMemoryMask);\r
- UINTN UncachedAddress;\r
-\r
- UncachedAddress = (UINTN)Address | UncachedMemoryMask;\r
-\r
- return (VOID *)UncachedAddress;\r
-}\r
-\r
-\r
-\r
-VOID *\r
-UncachedInternalAllocatePages (\r
- IN EFI_MEMORY_TYPE MemoryType,\r
- IN UINTN Pages\r
- )\r
-{\r
- return UncachedInternalAllocateAlignedPages (MemoryType, Pages, EFI_PAGE_SIZE);\r
-}\r
-\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocatePages (\r
- IN UINTN Pages\r
- )\r
-{\r
- return UncachedInternalAllocatePages (EfiBootServicesData, Pages);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateRuntimePages (\r
- IN UINTN Pages\r
- )\r
-{\r
- return UncachedInternalAllocatePages (EfiRuntimeServicesData, Pages);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateReservedPages (\r
- IN UINTN Pages\r
- )\r
-{\r
- return UncachedInternalAllocatePages (EfiReservedMemoryType, Pages);\r
-}\r
-\r
-\r
-\r
-VOID\r
-EFIAPI\r
-UncachedFreePages (\r
- IN VOID *Buffer,\r
- IN UINTN Pages\r
- )\r
-{\r
- UncachedFreeAlignedPages (Buffer, Pages);\r
- return;\r
-}\r
-\r
-\r
-VOID *\r
-UncachedInternalAllocateAlignedPages (\r
- IN EFI_MEMORY_TYPE MemoryType,\r
- IN UINTN Pages,\r
- IN UINTN Alignment\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS Memory;\r
- EFI_PHYSICAL_ADDRESS AlignedMemory;\r
- UINTN AlignmentMask;\r
- UINTN UnalignedPages;\r
- UINTN RealPages;\r
-\r
- //\r
- // Alignment must be a power of two or zero.\r
- //\r
- ASSERT ((Alignment & (Alignment - 1)) == 0);\r
-\r
- if (Pages == 0) {\r
- return NULL;\r
- }\r
- if (Alignment > EFI_PAGE_SIZE) {\r
- //\r
- // Caculate the total number of pages since alignment is larger than page size.\r
- //\r
- AlignmentMask = Alignment - 1;\r
- RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
- //\r
- // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.\r
- //\r
- ASSERT (RealPages > Pages);\r
-\r
- Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory);\r
- if (EFI_ERROR (Status)) {\r
- return NULL;\r
- }\r
- AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;\r
- UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);\r
- if (UnalignedPages > 0) {\r
- //\r
- // Free first unaligned page(s).\r
- //\r
- Status = gBS->FreePages (Memory, UnalignedPages);\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
- Memory = (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_TO_SIZE (Pages));\r
- UnalignedPages = RealPages - Pages - UnalignedPages;\r
- if (UnalignedPages > 0) {\r
- //\r
- // Free last unaligned page(s).\r
- //\r
- Status = gBS->FreePages (Memory, UnalignedPages);\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
- } else {\r
- //\r
- // Do not over-allocate pages in this case.\r
- //\r
- Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);\r
- if (EFI_ERROR (Status)) {\r
- return NULL;\r
- }\r
- AlignedMemory = (UINTN) Memory;\r
- }\r
-\r
- Status = gVirtualUncachedPages->ConvertPages (gVirtualUncachedPages, AlignedMemory, Pages * EFI_PAGE_SIZE, PcdGet64 (PcdArmUncachedMemoryMask), &gAttributes);\r
- if (EFI_ERROR (Status)) {\r
- return NULL;\r
- }\r
-\r
- AlignedMemory = (EFI_PHYSICAL_ADDRESS)(UINTN)ConvertToUncachedAddress ((VOID *)(UINTN)AlignedMemory);\r
-\r
- return (VOID *)(UINTN)AlignedMemory;\r
-}\r
-\r
-\r
-VOID\r
-EFIAPI\r
-UncachedFreeAlignedPages (\r
- IN VOID *Buffer,\r
- IN UINTN Pages\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS Memory;\r
-\r
- ASSERT (Pages != 0);\r
-\r
- Memory = ConvertToPhysicalAddress (Buffer);\r
-\r
- Status = gVirtualUncachedPages->RevertPages (gVirtualUncachedPages, Memory, Pages * EFI_PAGE_SIZE, PcdGet64 (PcdArmUncachedMemoryMask), gAttributes);\r
-\r
-\r
- Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Memory, Pages);\r
- ASSERT_EFI_ERROR (Status);\r
-}\r
-\r
-\r
-\r
-\r
-VOID *\r
-UncachedInternalAllocateAlignedPool (\r
- IN EFI_MEMORY_TYPE PoolType,\r
- IN UINTN AllocationSize,\r
- IN UINTN Alignment\r
- )\r
-{\r
- VOID *AlignedAddress;\r
-\r
- //\r
- // Alignment must be a power of two or zero.\r
- //\r
- ASSERT ((Alignment & (Alignment - 1)) == 0);\r
-\r
- if (Alignment < EFI_PAGE_SIZE) {\r
- Alignment = EFI_PAGE_SIZE;\r
- }\r
-\r
- AlignedAddress = UncachedInternalAllocateAlignedPages (PoolType, EFI_SIZE_TO_PAGES (AllocationSize), Alignment);\r
- if (AlignedAddress == NULL) {\r
- return NULL;\r
- }\r
-\r
- AddPagesToList ((VOID *)(UINTN)ConvertToPhysicalAddress (AlignedAddress), (VOID *)(UINTN)AlignedAddress, EFI_SIZE_TO_PAGES (AllocationSize));\r
-\r
- return (VOID *) AlignedAddress;\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateAlignedPool (\r
- IN UINTN AllocationSize,\r
- IN UINTN Alignment\r
- )\r
-{\r
- return UncachedInternalAllocateAlignedPool (EfiBootServicesData, AllocationSize, Alignment);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateAlignedRuntimePool (\r
- IN UINTN AllocationSize,\r
- IN UINTN Alignment\r
- )\r
-{\r
- return UncachedInternalAllocateAlignedPool (EfiRuntimeServicesData, AllocationSize, Alignment);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateAlignedReservedPool (\r
- IN UINTN AllocationSize,\r
- IN UINTN Alignment\r
- )\r
-{\r
- return UncachedInternalAllocateAlignedPool (EfiReservedMemoryType, AllocationSize, Alignment);\r
-}\r
-\r
-VOID *\r
-UncachedInternalAllocateAlignedZeroPool (\r
- IN EFI_MEMORY_TYPE PoolType,\r
- IN UINTN AllocationSize,\r
- IN UINTN Alignment\r
- )\r
-{\r
- VOID *Memory;\r
- Memory = UncachedInternalAllocateAlignedPool (PoolType, AllocationSize, Alignment);\r
- if (Memory != NULL) {\r
- Memory = ZeroMem (Memory, AllocationSize);\r
- }\r
- return Memory;\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateAlignedZeroPool (\r
- IN UINTN AllocationSize,\r
- IN UINTN Alignment\r
- )\r
-{\r
- return UncachedInternalAllocateAlignedZeroPool (EfiBootServicesData, AllocationSize, Alignment);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateAlignedRuntimeZeroPool (\r
- IN UINTN AllocationSize,\r
- IN UINTN Alignment\r
- )\r
-{\r
- return UncachedInternalAllocateAlignedZeroPool (EfiRuntimeServicesData, AllocationSize, Alignment);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateAlignedReservedZeroPool (\r
- IN UINTN AllocationSize,\r
- IN UINTN Alignment\r
- )\r
-{\r
- return UncachedInternalAllocateAlignedZeroPool (EfiReservedMemoryType, AllocationSize, Alignment);\r
-}\r
-\r
-VOID *\r
-UncachedInternalAllocateAlignedCopyPool (\r
- IN EFI_MEMORY_TYPE PoolType,\r
- IN UINTN AllocationSize,\r
- IN CONST VOID *Buffer,\r
- IN UINTN Alignment\r
- )\r
-{\r
- VOID *Memory;\r
-\r
- ASSERT (Buffer != NULL);\r
- ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));\r
-\r
- Memory = UncachedInternalAllocateAlignedPool (PoolType, AllocationSize, Alignment);\r
- if (Memory != NULL) {\r
- Memory = CopyMem (Memory, Buffer, AllocationSize);\r
- }\r
- return Memory;\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateAlignedCopyPool (\r
- IN UINTN AllocationSize,\r
- IN CONST VOID *Buffer,\r
- IN UINTN Alignment\r
- )\r
-{\r
- return UncachedInternalAllocateAlignedCopyPool (EfiBootServicesData, AllocationSize, Buffer, Alignment);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateAlignedRuntimeCopyPool (\r
- IN UINTN AllocationSize,\r
- IN CONST VOID *Buffer,\r
- IN UINTN Alignment\r
- )\r
-{\r
- return UncachedInternalAllocateAlignedCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer, Alignment);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateAlignedReservedCopyPool (\r
- IN UINTN AllocationSize,\r
- IN CONST VOID *Buffer,\r
- IN UINTN Alignment\r
- )\r
-{\r
- return UncachedInternalAllocateAlignedCopyPool (EfiReservedMemoryType, AllocationSize, Buffer, Alignment);\r
-}\r
-\r
-VOID\r
-EFIAPI\r
-UncachedFreeAlignedPool (\r
- IN VOID *Buffer\r
- )\r
-{\r
- VOID *Allocation;\r
- UINTN Pages;\r
-\r
- RemovePagesFromList (Buffer, &Allocation, &Pages);\r
-\r
- UncachedFreePages (Allocation, Pages);\r
-}\r
-\r
-VOID *\r
-UncachedInternalAllocatePool (\r
- IN EFI_MEMORY_TYPE MemoryType,\r
- IN UINTN AllocationSize\r
- )\r
-{\r
- UINTN CacheLineLength = ArmDataCacheLineLength ();\r
- return UncachedInternalAllocateAlignedPool (MemoryType, AllocationSize, CacheLineLength);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocatePool (\r
- IN UINTN AllocationSize\r
- )\r
-{\r
- return UncachedInternalAllocatePool (EfiBootServicesData, AllocationSize);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateRuntimePool (\r
- IN UINTN AllocationSize\r
- )\r
-{\r
- return UncachedInternalAllocatePool (EfiRuntimeServicesData, AllocationSize);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateReservedPool (\r
- IN UINTN AllocationSize\r
- )\r
-{\r
- return UncachedInternalAllocatePool (EfiReservedMemoryType, AllocationSize);\r
-}\r
-\r
-VOID *\r
-UncachedInternalAllocateZeroPool (\r
- IN EFI_MEMORY_TYPE PoolType,\r
- IN UINTN AllocationSize\r
- )\r
-{\r
- VOID *Memory;\r
-\r
- Memory = UncachedInternalAllocatePool (PoolType, AllocationSize);\r
- if (Memory != NULL) {\r
- Memory = ZeroMem (Memory, AllocationSize);\r
- }\r
- return Memory;\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateZeroPool (\r
- IN UINTN AllocationSize\r
- )\r
-{\r
- return UncachedInternalAllocateZeroPool (EfiBootServicesData, AllocationSize);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateRuntimeZeroPool (\r
- IN UINTN AllocationSize\r
- )\r
-{\r
- return UncachedInternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateReservedZeroPool (\r
- IN UINTN AllocationSize\r
- )\r
-{\r
- return UncachedInternalAllocateZeroPool (EfiReservedMemoryType, AllocationSize);\r
-}\r
-\r
-VOID *\r
-UncachedInternalAllocateCopyPool (\r
- IN EFI_MEMORY_TYPE PoolType,\r
- IN UINTN AllocationSize,\r
- IN CONST VOID *Buffer\r
- )\r
-{\r
- VOID *Memory;\r
-\r
- ASSERT (Buffer != NULL);\r
- ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));\r
-\r
- Memory = UncachedInternalAllocatePool (PoolType, AllocationSize);\r
- if (Memory != NULL) {\r
- Memory = CopyMem (Memory, Buffer, AllocationSize);\r
- }\r
- return Memory;\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateCopyPool (\r
- IN UINTN AllocationSize,\r
- IN CONST VOID *Buffer\r
- )\r
-{\r
- return UncachedInternalAllocateCopyPool (EfiBootServicesData, AllocationSize, Buffer);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateRuntimeCopyPool (\r
- IN UINTN AllocationSize,\r
- IN CONST VOID *Buffer\r
- )\r
-{\r
- return UncachedInternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);\r
-}\r
-\r
-VOID *\r
-EFIAPI\r
-UncachedAllocateReservedCopyPool (\r
- IN UINTN AllocationSize,\r
- IN CONST VOID *Buffer\r
- )\r
-{\r
- return UncachedInternalAllocateCopyPool (EfiReservedMemoryType, AllocationSize, Buffer);\r
-}\r
-\r
-VOID\r
-EFIAPI\r
-UncachedFreePool (\r
- IN VOID *Buffer\r
- )\r
-{\r
- UncachedFreeAlignedPool (Buffer);\r
-}\r
-\r
-VOID\r
-EFIAPI\r
-UncachedSafeFreePool (\r
- IN VOID *Buffer\r
- )\r
-{\r
- if (Buffer != NULL) {\r
- UncachedFreePool (Buffer);\r
- Buffer = NULL;\r
- }\r
-}\r
-\r
-/**\r
- The constructor function caches the pointer of DXE Services Table.\r
-\r
- The constructor function caches the pointer of DXE Services Table.\r
- It will ASSERT() if that operation fails.\r
- It will ASSERT() if the pointer of DXE Services Table is NULL.\r
- It will always return EFI_SUCCESS.\r
-\r
- @param ImageHandle The firmware allocated handle for the EFI image.\r
- @param SystemTable A pointer to the EFI System Table.\r
-\r
- @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-DebugUncachedMemoryAllocationLibConstructor (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gDebugUncachedCpu);\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- Status = gBS->LocateProtocol (&gVirtualUncachedPagesProtocolGuid, NULL, (VOID **)&gVirtualUncachedPages);\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- return Status;\r
-}\r
-\r
-\r
-\r