]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.c
Adding support for BeagleBoard.
[mirror_edk2.git] / ArmPkg / Library / UncachedMemoryAllocationLib / UncachedMemoryAllocationLib.c
diff --git a/ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.c b/ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.c
new file mode 100644 (file)
index 0000000..060ba6b
--- /dev/null
@@ -0,0 +1,626 @@
+/** @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