]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.c
Clean up UncachedMemoryAllocationLib to use CPU AP.
[mirror_edk2.git] / ArmPkg / Library / UncachedMemoryAllocationLib / UncachedMemoryAllocationLib.c
index 830212e4d7ade9139c275304783db51c4fea92ee..fa683e19ed23cf4b56b06964f45a09a42e9fdc5c 100644 (file)
@@ -1,6 +1,8 @@
 /** @file\r
 /** @file\r
+  UncachedMemoryAllocation lib that uses DXE CPU driver to chnage cachability for\r
+  a buffer.\r
 \r
 \r
-  Copyright (c) 2008-2009, Apple Inc. All rights reserved.\r
+  Copyright (c) 2008-2010, 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
   \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
 \r
 **/\r
 \r
 \r
 **/\r
 \r
+#include <Library/BaseLib.h>\r
 #include <Library/BaseMemoryLib.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 <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 <Library/DxeServicesTableLib.h>\r
+\r
 #include <Protocol/Cpu.h>\r
 \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
+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
-  PhysicalAddress = (UINTN)VirtualAddress & ~UncachedMemoryMask;\r
   \r
   \r
-  return (EFI_PHYSICAL_ADDRESS)PhysicalAddress;\r
-}\r
 \r
 \r
-VOID *\r
-ConvertToCachedAddress (\r
-  IN VOID *Address\r
-  )\r
-{\r
-  return (VOID *)(UINTN)ConvertToPhysicalAddress(Address);\r
-}\r
+EFI_CPU_ARCH_PROTOCOL           *gDebugUncachedCpu;\r
 \r
 \r
-VOID *\r
-ConvertToUncachedAddress (\r
-  IN VOID *Address\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        *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
   )\r
 {\r
-  UINTN UncachedMemoryMask = (UINTN)PcdGet64(PcdArmUncachedMemoryMask);\r
-  UINTN UncachedAddress;\r
+  FREE_PAGE_NODE  *NewNode;\r
   \r
   \r
-  UncachedAddress = (UINTN)Address | UncachedMemoryMask;\r
+  NewNode = AllocatePool (sizeof (LIST_ENTRY));\r
+  if (NewNode == NULL) {\r
+    ASSERT (FALSE);\r
+    return;\r
+  }\r
   \r
   \r
-  return (VOID *)UncachedAddress;\r
+  NewNode->Allocation = Allocation;\r
+  NewNode->Pages      = Pages;\r
+  \r
+  InsertTailList (&mPageList, &NewNode->Link);\r
 }\r
 \r
 }\r
 \r
+\r
 VOID\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
   )\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
   \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
+\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
 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
 \r
+\r
 VOID *\r
 EFIAPI\r
 UncachedAllocatePages (\r
 VOID *\r
 EFIAPI\r
 UncachedAllocatePages (\r
@@ -123,6 +157,8 @@ UncachedAllocateReservedPages (
   return UncachedInternalAllocatePages (EfiReservedMemoryType, Pages);\r
 }\r
 \r
   return UncachedInternalAllocatePages (EfiReservedMemoryType, Pages);\r
 }\r
 \r
+\r
+\r
 VOID\r
 EFIAPI\r
 UncachedFreePages (\r
 VOID\r
 EFIAPI\r
 UncachedFreePages (\r
@@ -130,16 +166,11 @@ UncachedFreePages (
   IN UINTN  Pages\r
   )\r
 {\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
+  UncachedFreeAlignedPages (Buffer, Pages);\r
+  return;\r
 }\r
 \r
 }\r
 \r
+\r
 VOID *\r
 UncachedInternalAllocateAlignedPages (\r
   IN EFI_MEMORY_TYPE  MemoryType,  \r
 VOID *\r
 UncachedInternalAllocateAlignedPages (\r
   IN EFI_MEMORY_TYPE  MemoryType,  \r
@@ -147,12 +178,13 @@ UncachedInternalAllocateAlignedPages (
   IN UINTN            Alignment\r
   )\r
 {\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
+  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
 \r
   //\r
   // Alignment must be a power of two or zero.\r
@@ -206,43 +238,20 @@ UncachedInternalAllocateAlignedPages (
     AlignedMemory  = (UINTN) Memory;\r
   }\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
+  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
   }\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
+  Status = gDebugUncachedCpu->SetMemoryAttributes (gDebugUncachedCpu, Memory, EFI_PAGES_TO_SIZE (Pages), EFI_MEMORY_UC);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+  \r
+  return (VOID *)(UINTN)Memory;\r
 }\r
 \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
 \r
 VOID\r
 EFIAPI\r
@@ -251,16 +260,21 @@ UncachedFreeAlignedPages (
   IN UINTN  Pages\r
   )\r
 {\r
   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
 \r
   ASSERT (Pages != 0);\r
   \r
-  Buffer = ConvertToCachedAddress(Buffer);\r
+  Memory = (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer;\r
+  Status = gDebugUncachedCpu->SetMemoryAttributes (gDebugUncachedCpu, Memory, EFI_PAGES_TO_SIZE (Pages), gAttributes);\r
   \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
   ASSERT_EFI_ERROR (Status);\r
 }\r
 \r
+\r
+\r
+\r
 VOID *\r
 UncachedInternalAllocateAlignedPool (\r
   IN EFI_MEMORY_TYPE  PoolType,\r
 VOID *\r
 UncachedInternalAllocateAlignedPool (\r
   IN EFI_MEMORY_TYPE  PoolType,\r
@@ -268,59 +282,23 @@ UncachedInternalAllocateAlignedPool (
   IN UINTN            Alignment\r
   )\r
 {\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
+  VOID      *AlignedAddress;\r
+  \r
   //\r
   // Alignment must be a power of two or zero.\r
   //\r
   ASSERT ((Alignment & (Alignment - 1)) == 0);\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
     \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
     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
 \r
   return (VOID *) AlignedAddress;\r
 }\r
@@ -456,23 +434,14 @@ UncachedAllocateAlignedReservedCopyPool (
 VOID\r
 EFIAPI\r
 UncachedFreeAlignedPool (\r
 VOID\r
 EFIAPI\r
 UncachedFreeAlignedPool (\r
-  IN VOID   *Buffer\r
+  IN VOID   *Allocation\r
   )\r
 {\r
   )\r
 {\r
-  VOID        *RawAddress;\r
-  VOID        **FreePointer;\r
-  EFI_STATUS  Status;\r
-\r
-  Buffer = ConvertToCachedAddress(Buffer);\r
+  UINTN   Pages;\r
   \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
 \r
-  Status = gBS->FreePool (RawAddress);\r
-  ASSERT_EFI_ERROR (Status);\r
+  UncachedFreePages (Allocation, Pages);\r
 }\r
 \r
 VOID *\r
 }\r
 \r
 VOID *\r
@@ -481,8 +450,8 @@ UncachedInternalAllocatePool (
   IN UINTN            AllocationSize\r
   )\r
 {\r
   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
 }\r
 \r
 VOID *\r
@@ -609,7 +578,7 @@ UncachedFreePool (
   IN VOID   *Buffer\r
   )\r
 {\r
   IN VOID   *Buffer\r
   )\r
 {\r
-  UncachedFreeAlignedPool(Buffer);\r
+  UncachedFreeAlignedPool (Buffer);\r
 }\r
 \r
 VOID\r
 }\r
 \r
 VOID\r
@@ -624,3 +593,35 @@ UncachedSafeFreePool (
   }\r
 }\r
 \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
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r