/** @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
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
-}\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
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
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
}\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