X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=ArmPkg%2FLibrary%2FArmDmaLib%2FArmDmaLib.c;h=e836feff1ef85db9af53341780fc95a76699571e;hp=66f3469eb1b5805e6211233bff48b02341111f4e;hb=de2ec785e2b11798a3ca7aaf653bc76576d947b0;hpb=80e5a33da1fcbe54cbcc178f1880e80e297d5fd4 diff --git a/ArmPkg/Library/ArmDmaLib/ArmDmaLib.c b/ArmPkg/Library/ArmDmaLib/ArmDmaLib.c index 66f3469eb1..e836feff1e 100644 --- a/ArmPkg/Library/ArmDmaLib/ArmDmaLib.c +++ b/ArmPkg/Library/ArmDmaLib/ArmDmaLib.c @@ -22,7 +22,6 @@ #include #include #include -#include #include @@ -36,8 +35,7 @@ typedef struct { -EFI_CPU_ARCH_PROTOCOL *gCpu; -UINTN gCacheAlignment = 0; +STATIC EFI_CPU_ARCH_PROTOCOL *mCpu; /** Provides the DMA controller-specific addresses needed to access system memory. @@ -90,21 +88,30 @@ DmaMap ( return EFI_OUT_OF_RESOURCES; } - *Mapping = Map; - - if ((((UINTN)HostAddress & (gCacheAlignment - 1)) != 0) || - ((*NumberOfBytes & (gCacheAlignment - 1)) != 0)) { + if ((((UINTN)HostAddress & (mCpu->DmaBufferAlignment - 1)) != 0) || + ((*NumberOfBytes & (mCpu->DmaBufferAlignment - 1)) != 0)) { // Get the cacheability of the region Status = gDS->GetMemorySpaceDescriptor (*DeviceAddress, &GcdDescriptor); if (EFI_ERROR(Status)) { - return Status; + goto FreeMapInfo; } // If the mapped buffer is not an uncached buffer - if ( (GcdDescriptor.Attributes != EFI_MEMORY_WC) && - (GcdDescriptor.Attributes != EFI_MEMORY_UC) ) - { + if ((GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) != 0) { + // + // Operations of type MapOperationBusMasterCommonBuffer are only allowed + // on uncached buffers. + // + if (Operation == MapOperationBusMasterCommonBuffer) { + DEBUG ((EFI_D_ERROR, + "%a: Operation type 'MapOperationBusMasterCommonBuffer' is only supported\n" + "on memory regions that were allocated using DmaAllocateBuffer ()\n", + __FUNCTION__)); + Status = EFI_UNSUPPORTED; + goto FreeMapInfo; + } + // // If the buffer does not fill entire cache lines we must double buffer into // uncached memory. Device (PCI) address becomes uncached page. @@ -112,10 +119,10 @@ DmaMap ( Map->DoubleBuffer = TRUE; Status = DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (*NumberOfBytes), &Buffer); if (EFI_ERROR (Status)) { - return Status; + goto FreeMapInfo; } - if ((Operation == MapOperationBusMasterRead) || (Operation == MapOperationBusMasterCommonBuffer)) { + if (Operation == MapOperationBusMasterRead) { CopyMem (Buffer, HostAddress, *NumberOfBytes); } @@ -126,14 +133,26 @@ DmaMap ( } else { Map->DoubleBuffer = FALSE; - // Flush the Data Cache (should not have any effect if the memory region is uncached) - gCpu->FlushDataCache (gCpu, *DeviceAddress, *NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate); + DEBUG_CODE_BEGIN (); - if ((Operation == MapOperationBusMasterRead) || (Operation == MapOperationBusMasterCommonBuffer)) { - // In case the buffer is used for instance to send command to a PCI controller, we must ensure the memory is uncached - Status = gDS->SetMemorySpaceAttributes (*DeviceAddress & ~(BASE_4KB - 1), ALIGN_VALUE (*NumberOfBytes, BASE_4KB), EFI_MEMORY_WC); - ASSERT_EFI_ERROR (Status); - } + // + // The operation type check above only executes if the buffer happens to be + // misaligned with respect to CWG, but even if it is aligned, we should not + // allow arbitrary buffers to be used for creating consistent mappings. + // So duplicate the check here when running in DEBUG mode, just to assert + // that we are not trying to create a consistent mapping for cached memory. + // + Status = gDS->GetMemorySpaceDescriptor (*DeviceAddress, &GcdDescriptor); + ASSERT_EFI_ERROR(Status); + + ASSERT (Operation != MapOperationBusMasterCommonBuffer || + (GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) == 0); + + DEBUG_CODE_END (); + + // Flush the Data Cache (should not have any effect if the memory region is uncached) + mCpu->FlushDataCache (mCpu, *DeviceAddress, *NumberOfBytes, + EfiCpuFlushTypeWriteBackInvalidate); } Map->HostAddress = (UINTN)HostAddress; @@ -141,7 +160,14 @@ DmaMap ( Map->NumberOfBytes = *NumberOfBytes; Map->Operation = Operation; + *Mapping = Map; + return EFI_SUCCESS; + +FreeMapInfo: + FreePool (Map); + + return Status; } @@ -153,6 +179,8 @@ DmaMap ( @retval EFI_SUCCESS The range was unmapped. @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. + @retval EFI_INVALID_PARAMETER An inconsistency was detected between the mapping type + and the DoubleBuffer field **/ EFI_STATUS @@ -162,6 +190,7 @@ DmaUnmap ( ) { MAP_INFO_INSTANCE *Map; + EFI_STATUS Status; if (Mapping == NULL) { ASSERT (FALSE); @@ -170,8 +199,13 @@ DmaUnmap ( Map = (MAP_INFO_INSTANCE *)Mapping; + Status = EFI_SUCCESS; if (Map->DoubleBuffer) { - if ((Map->Operation == MapOperationBusMasterWrite) || (Map->Operation == MapOperationBusMasterCommonBuffer)) { + ASSERT (Map->Operation != MapOperationBusMasterCommonBuffer); + + if (Map->Operation == MapOperationBusMasterCommonBuffer) { + Status = EFI_INVALID_PARAMETER; + } else if (Map->Operation == MapOperationBusMasterWrite) { CopyMem ((VOID *)(UINTN)Map->HostAddress, (VOID *)(UINTN)Map->DeviceAddress, Map->NumberOfBytes); } @@ -182,13 +216,14 @@ DmaUnmap ( // // Make sure we read buffer from uncached memory and not the cache // - gCpu->FlushDataCache (gCpu, Map->HostAddress, Map->NumberOfBytes, EfiCpuFlushTypeInvalidate); + mCpu->FlushDataCache (mCpu, Map->HostAddress, Map->NumberOfBytes, + EfiCpuFlushTypeInvalidate); } } FreePool (Map); - return EFI_SUCCESS; + return Status; } /** @@ -282,11 +317,9 @@ ArmDmaLibConstructor ( EFI_STATUS Status; // Get the Cpu protocol for later use - Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu); + Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu); ASSERT_EFI_ERROR(Status); - gCacheAlignment = ArmCacheWritebackGranule (); - return Status; }