]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.c
ArmPkg/UncachedMemoryAllocationLib: Removed unused header (Protocol/Cpu.h)
[mirror_edk2.git] / ArmPkg / Library / UncachedMemoryAllocationLib / UncachedMemoryAllocationLib.c
index 830212e4d7ade9139c275304783db51c4fea92ee..a24300312e240f48468203897407cb9232c5459a 100644 (file)
@@ -1,8 +1,10 @@
 /** @file\r
+  UncachedMemoryAllocation lib that uses DXE Service to change cachability for\r
+  a buffer.\r
 \r
-  Copyright (c) 2008-2009, Apple Inc. All rights reserved.\r
+  Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
   \r
-  All rights reserved. This program and the accompanying materials\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
 **/\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
-#include <Protocol/Cpu.h>\r
+#include <Library/DxeServicesTableLib.h>\r
 \r
-EFI_PHYSICAL_ADDRESS\r
-ConvertToPhysicalAddress (\r
-  IN VOID *VirtualAddress\r
-  )\r
-{\r
-  UINTN UncachedMemoryMask = (UINTN)PcdGet64(PcdArmUncachedMemoryMask);\r
-  UINTN PhysicalAddress;\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
-  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
+// Assume all of memory has the same cache attributes, unless we do our magic\r
+//\r
+UINT64  gAttributes;\r
 \r
-VOID *\r
-ConvertToUncachedAddress (\r
-  IN VOID *Address\r
+typedef struct {\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   *Allocation,\r
+  UINTN     Pages\r
   )\r
 {\r
-  UINTN UncachedMemoryMask = (UINTN)PcdGet64(PcdArmUncachedMemoryMask);\r
-  UINTN UncachedAddress;\r
+  FREE_PAGE_NODE  *NewNode;\r
+  \r
+  NewNode = AllocatePool (sizeof (LIST_ENTRY));\r
+  if (NewNode == NULL) {\r
+    ASSERT (FALSE);\r
+    return;\r
+  }\r
   \r
-  UncachedAddress = (UINTN)Address | UncachedMemoryMask;\r
+  NewNode->Allocation = Allocation;\r
+  NewNode->Pages      = Pages;\r
   \r
-  return (VOID *)UncachedAddress;\r
+  InsertTailList (&mPageList, &NewNode->Link);\r
 }\r
 \r
+\r
 VOID\r
-FlushCache (\r
-  IN EFI_PHYSICAL_ADDRESS Address,\r
-  IN UINTN                Size\r
+RemovePagesFromList (\r
+  OUT VOID  *Allocation,\r
+  OUT UINTN *Pages\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
+  LIST_ENTRY      *Link;\r
+  FREE_PAGE_NODE  *OldNode;\r
+\r
+  *Pages = 0;\r
   \r
-  Status = Cpu->FlushDataCache(Cpu, Address, Size, EfiCpuFlushTypeWriteBackInvalidate);\r
-  ASSERT_EFI_ERROR(Status);\r
+  for (Link = mPageList.ForwardLink; Link != &mPageList; Link = Link->ForwardLink) {\r
+    OldNode = BASE_CR (Link, FREE_PAGE_NODE, Link);\r
+    if (OldNode->Allocation == 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
+  Converts a cached or uncached address to a physical address suitable for use in SoC registers.\r
+\r
+  @param  VirtualAddress                 The pointer to convert.\r
+\r
+  @return The physical address of the supplied virtual pointer.\r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+ConvertToPhysicalAddress (\r
+  IN VOID *VirtualAddress\r
+  )\r
+{\r
+  return (EFI_PHYSICAL_ADDRESS)(UINTN)VirtualAddress;\r
 }\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
+  return UncachedInternalAllocateAlignedPages (MemoryType, Pages, EFI_PAGE_SIZE);\r
 }\r
 \r
+\r
 VOID *\r
 EFIAPI\r
 UncachedAllocatePages (\r
@@ -123,6 +154,8 @@ UncachedAllocateReservedPages (
   return UncachedInternalAllocatePages (EfiReservedMemoryType, Pages);\r
 }\r
 \r
+\r
+\r
 VOID\r
 EFIAPI\r
 UncachedFreePages (\r
@@ -130,16 +163,11 @@ UncachedFreePages (
   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
+  UncachedFreeAlignedPages (Buffer, Pages);\r
+  return;\r
 }\r
 \r
+\r
 VOID *\r
 UncachedInternalAllocateAlignedPages (\r
   IN EFI_MEMORY_TYPE  MemoryType,  \r
@@ -147,12 +175,13 @@ UncachedInternalAllocateAlignedPages (
   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
+  EFI_STATUS                        Status;\r
+  EFI_PHYSICAL_ADDRESS              Memory;\r
+  EFI_PHYSICAL_ADDRESS              AlignedMemory;\r
+  UINTN                             AlignmentMask;\r
+  UINTN                             UnalignedPages;\r
+  UINTN                             RealPages;\r
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR   Descriptor;\r
 \r
   //\r
   // Alignment must be a power of two or zero.\r
@@ -206,43 +235,18 @@ UncachedInternalAllocateAlignedPages (
     AlignedMemory  = (UINTN) Memory;\r
   }\r
   \r
-  if (AlignedMemory != 0) {\r
-    FlushCache (AlignedMemory, EFI_PAGES_TO_SIZE(Pages));\r
-    AlignedMemory = (UINTN)ConvertToUncachedAddress((VOID *)AlignedMemory);\r
+  Status = gDS->GetMemorySpaceDescriptor (Memory, &Descriptor);\r
+  if (!EFI_ERROR (Status)) {\r
+    // We are making an assumption that all of memory has the same default attributes\r
+    gAttributes = Descriptor.Attributes;\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
+  Status = gDS->SetMemorySpaceAttributes (Memory, EFI_PAGES_TO_SIZE (Pages), EFI_MEMORY_WC);\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  return (VOID *)(UINTN)Memory;\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
@@ -251,16 +255,21 @@ UncachedFreeAlignedPages (
   IN UINTN  Pages\r
   )\r
 {\r
-  EFI_STATUS  Status;\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  Memory; \r
 \r
   ASSERT (Pages != 0);\r
   \r
-  Buffer = ConvertToCachedAddress(Buffer);\r
+  Memory = (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer;\r
+  Status = gDS->SetMemorySpaceAttributes (Memory, EFI_PAGES_TO_SIZE (Pages), gAttributes);\r
   \r
-  Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);\r
+  Status = gBS->FreePages (Memory, Pages);\r
   ASSERT_EFI_ERROR (Status);\r
 }\r
 \r
+\r
+\r
+\r
 VOID *\r
 UncachedInternalAllocateAlignedPool (\r
   IN EFI_MEMORY_TYPE  PoolType,\r
@@ -268,59 +277,23 @@ UncachedInternalAllocateAlignedPool (
   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
+  VOID      *AlignedAddress;\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
+  if (Alignment < EFI_PAGE_SIZE) {\r
+    Alignment = EFI_PAGE_SIZE;\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
+  AlignedAddress = UncachedInternalAllocateAlignedPages (PoolType, EFI_SIZE_TO_PAGES (AllocationSize), Alignment);\r
+  if (AlignedAddress == NULL) {\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
+  AddPagesToList ((VOID *)(UINTN)AlignedAddress, EFI_SIZE_TO_PAGES (AllocationSize));\r
 \r
   return (VOID *) AlignedAddress;\r
 }\r
@@ -456,23 +429,14 @@ UncachedAllocateAlignedReservedCopyPool (
 VOID\r
 EFIAPI\r
 UncachedFreeAlignedPool (\r
-  IN VOID   *Buffer\r
+  IN VOID   *Allocation\r
   )\r
 {\r
-  VOID        *RawAddress;\r
-  VOID        **FreePointer;\r
-  EFI_STATUS  Status;\r
-\r
-  Buffer = ConvertToCachedAddress(Buffer);\r
+  UINTN   Pages;\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
+  RemovePagesFromList (Allocation, &Pages);\r
 \r
-  Status = gBS->FreePool (RawAddress);\r
-  ASSERT_EFI_ERROR (Status);\r
+  UncachedFreePages (Allocation, Pages);\r
 }\r
 \r
 VOID *\r
@@ -481,8 +445,8 @@ UncachedInternalAllocatePool (
   IN UINTN            AllocationSize\r
   )\r
 {\r
-  UINTN CacheLineLength = ArmDataCacheLineLength();\r
-  return UncachedInternalAllocateAlignedPool(MemoryType, AllocationSize, CacheLineLength);\r
+  UINTN CacheLineLength = ArmDataCacheLineLength ();\r
+  return UncachedInternalAllocateAlignedPool (MemoryType, AllocationSize, CacheLineLength);\r
 }\r
 \r
 VOID *\r
@@ -609,7 +573,7 @@ UncachedFreePool (
   IN VOID   *Buffer\r
   )\r
 {\r
-  UncachedFreeAlignedPool(Buffer);\r
+  UncachedFreeAlignedPool (Buffer);\r
 }\r
 \r
 VOID\r