]> 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
+  UncachedMemoryAllocation lib that uses DXE CPU driver to chnage 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.\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
+#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 <Library/DxeServicesTableLib.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
-  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
+EFI_CPU_ARCH_PROTOCOL           *gDebugUncachedCpu;\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
-  UINTN UncachedMemoryMask = (UINTN)PcdGet64(PcdArmUncachedMemoryMask);\r
-  UINTN UncachedAddress;\r
+  FREE_PAGE_NODE  *NewNode;\r
   \r
-  UncachedAddress = (UINTN)Address | UncachedMemoryMask;\r
+  NewNode = AllocatePool (sizeof (LIST_ENTRY));\r
+  if (NewNode == NULL) {\r
+    ASSERT (FALSE);\r
+    return;\r
+  }\r
   \r
-  return (VOID *)UncachedAddress;\r
+  NewNode->Allocation = Allocation;\r
+  NewNode->Pages      = Pages;\r
+  \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 +157,8 @@ UncachedAllocateReservedPages (
   return UncachedInternalAllocatePages (EfiReservedMemoryType, Pages);\r
 }\r
 \r
+\r
+\r
 VOID\r
 EFIAPI\r
 UncachedFreePages (\r
@@ -130,16 +166,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 +178,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 +238,20 @@ 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
-}\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
-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 +260,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 = gDebugUncachedCpu->SetMemoryAttributes (gDebugUncachedCpu, 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 +282,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 +434,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 +450,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 +578,7 @@ UncachedFreePool (
   IN VOID   *Buffer\r
   )\r
 {\r
-  UncachedFreeAlignedPool(Buffer);\r
+  UncachedFreeAlignedPool (Buffer);\r
 }\r
 \r
 VOID\r
@@ -624,3 +593,35 @@ UncachedSafeFreePool (
   }\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