--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2008-2009, Apple Inc. All rights reserved.\r
+ \r
+ All rights reserved. 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 <Library/BaseMemoryLib.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
+#include <Protocol/Cpu.h>\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
+VOID *\r
+ConvertToCachedAddress (\r
+ IN VOID *Address\r
+ )\r
+{\r
+ return (VOID *)(UINTN)ConvertToPhysicalAddress(Address);\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
+VOID\r
+FlushCache (\r
+ IN EFI_PHYSICAL_ADDRESS Address,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ EFI_CPU_ARCH_PROTOCOL *Cpu;\r
+ EFI_STATUS Status;\r
+ \r
+ Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);\r
+ ASSERT_EFI_ERROR(Status);\r
+ \r
+ Status = Cpu->FlushDataCache(Cpu, Address, Size, EfiCpuFlushTypeWriteBackInvalidate);\r
+ ASSERT_EFI_ERROR(Status);\r
+}\r
+\r
+VOID *\r
+UncachedInternalAllocatePages (\r
+ IN EFI_MEMORY_TYPE MemoryType, \r
+ IN UINTN Pages\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS Memory; \r
+\r
+ if (Pages == 0) {\r
+ return NULL;\r
+ }\r
+\r
+ Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);\r
+ if (EFI_ERROR (Status)) {\r
+ Memory = 0;\r
+ }\r
+ \r
+ if (Memory != 0) {\r
+ FlushCache(Memory, EFI_PAGES_TO_SIZE(Pages));\r
+ Memory = (EFI_PHYSICAL_ADDRESS)(UINTN)ConvertToUncachedAddress((VOID *)(UINTN)Memory);\r
+ }\r
+ \r
+ return (VOID *) (UINTN) Memory;\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
+VOID\r
+EFIAPI\r
+UncachedFreePages (\r
+ IN VOID *Buffer,\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Pages != 0);\r
+ \r
+ Buffer = ConvertToCachedAddress(Buffer);\r
+ \r
+ Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);\r
+ ASSERT_EFI_ERROR (Status);\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
+ UINTN 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
+ if (AlignedMemory != 0) {\r
+ FlushCache(AlignedMemory, EFI_PAGES_TO_SIZE(Pages));\r
+ AlignedMemory = (UINTN)ConvertToUncachedAddress((VOID *)AlignedMemory);\r
+ }\r
+ \r
+ return (VOID *) AlignedMemory;\r
+}\r
+\r
+VOID *\r
+EFIAPI\r
+UncachedAllocateAlignedPages (\r
+ IN UINTN Pages,\r
+ IN UINTN Alignment\r
+ )\r
+{\r
+ return UncachedInternalAllocateAlignedPages (EfiBootServicesData, Pages, Alignment);\r
+}\r
+\r
+VOID *\r
+EFIAPI\r
+UncachedAllocateAlignedRuntimePages (\r
+ IN UINTN Pages,\r
+ IN UINTN Alignment\r
+ )\r
+{\r
+ return UncachedInternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);\r
+}\r
+\r
+VOID *\r
+EFIAPI\r
+UncachedAllocateAlignedReservedPages (\r
+ IN UINTN Pages,\r
+ IN UINTN Alignment\r
+ )\r
+{\r
+ return UncachedInternalAllocateAlignedPages (EfiReservedMemoryType, Pages, Alignment);\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+UncachedFreeAlignedPages (\r
+ IN VOID *Buffer,\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Pages != 0);\r
+ \r
+ Buffer = ConvertToCachedAddress(Buffer);\r
+ \r
+ Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);\r
+ ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+VOID *\r
+UncachedInternalAllocateAlignedPool (\r
+ IN EFI_MEMORY_TYPE PoolType,\r
+ IN UINTN AllocationSize,\r
+ IN UINTN Alignment\r
+ )\r
+{\r
+ VOID *RawAddress;\r
+ UINTN AlignedAddress;\r
+ UINTN AlignmentMask;\r
+ UINTN OverAllocationSize;\r
+ UINTN RealAllocationSize;\r
+ VOID **FreePointer;\r
+ UINTN DataCacheLineLength;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Alignment must be a power of two or zero.\r
+ //\r
+ ASSERT ((Alignment & (Alignment - 1)) == 0);\r
+\r
+ DataCacheLineLength = ArmDataCacheLineLength();\r
+ \r
+ // Alignment must be at least cache-line aligned\r
+ if (Alignment < DataCacheLineLength) {\r
+ Alignment = DataCacheLineLength;\r
+ }\r
+ \r
+ if (Alignment == 0) {\r
+ AlignmentMask = Alignment;\r
+ } else {\r
+ AlignmentMask = Alignment - 1;\r
+ }\r
+ \r
+ //\r
+ // Calculate the extra memory size, over-allocate memory pool and get the aligned memory address. \r
+ //\r
+ OverAllocationSize = sizeof (RawAddress) + AlignmentMask;\r
+ RealAllocationSize = AllocationSize + OverAllocationSize;\r
+ //\r
+ // Make sure that AllocationSize plus OverAllocationSize does not overflow. \r
+ //\r
+ ASSERT (RealAllocationSize > AllocationSize); \r
+\r
+ Status = gBS->AllocatePool (PoolType, RealAllocationSize, &RawAddress);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ AlignedAddress = ((UINTN) RawAddress + OverAllocationSize) & ~AlignmentMask;\r
+ //\r
+ // Save the original memory address just before the aligned address.\r
+ //\r
+ FreePointer = (VOID **)(AlignedAddress - sizeof (RawAddress));\r
+ *FreePointer = RawAddress;\r
+\r
+ if (AlignedAddress != 0) {\r
+ FlushCache(AlignedAddress, AllocationSize);\r
+ AlignedAddress = (UINTN)ConvertToUncachedAddress((VOID *)AlignedAddress);\r
+ }\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 *RawAddress;\r
+ VOID **FreePointer;\r
+ EFI_STATUS Status;\r
+\r
+ Buffer = ConvertToCachedAddress(Buffer);\r
+ \r
+ //\r
+ // Get the pre-saved original address in the over-allocate pool.\r
+ //\r
+ FreePointer = (VOID **)((UINTN) Buffer - sizeof (RawAddress));\r
+ RawAddress = *FreePointer;\r
+\r
+ Status = gBS->FreePool (RawAddress);\r
+ ASSERT_EFI_ERROR (Status);\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