/** @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
return UncachedInternalAllocatePages (EfiReservedMemoryType, Pages);\r
}\r
\r
+\r
+\r
VOID\r
EFIAPI\r
UncachedFreePages (\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
VOID *\r
UncachedInternalAllocateAlignedPages (\r
IN EFI_MEMORY_TYPE MemoryType, \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
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
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
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
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
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
IN VOID *Buffer\r
)\r
{\r
- UncachedFreeAlignedPool(Buffer);\r
+ UncachedFreeAlignedPool (Buffer);\r
}\r
\r
VOID\r