The non-coherent DmaLib implementation in ArmDmaLib no longer relies on anything in ArmPkg. So clone it into EmbeddedPkg, and rename it to NonCoherentDmaLib. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
		
			
				
	
	
		
			492 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			492 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
 | 
						|
  Generic non-coherent implementation of DmaLib.h
 | 
						|
 | 
						|
  Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
 | 
						|
  Copyright (c) 2015 - 2017, Linaro, Ltd. All rights reserved.<BR>
 | 
						|
 | 
						|
  This program and the accompanying materials are licensed and made
 | 
						|
  available under the terms and conditions of the BSD License which
 | 
						|
  accompanies this distribution.  The full text of the license may be
 | 
						|
  found at http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
 | 
						|
  IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include <PiDxe.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/DmaLib.h>
 | 
						|
#include <Library/DxeServicesTableLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/UefiBootServicesTableLib.h>
 | 
						|
#include <Library/IoLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
 | 
						|
#include <Protocol/Cpu.h>
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  EFI_PHYSICAL_ADDRESS      HostAddress;
 | 
						|
  VOID                      *BufferAddress;
 | 
						|
  UINTN                     NumberOfBytes;
 | 
						|
  DMA_MAP_OPERATION         Operation;
 | 
						|
  BOOLEAN                   DoubleBuffer;
 | 
						|
} MAP_INFO_INSTANCE;
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  LIST_ENTRY          Link;
 | 
						|
  VOID                *HostAddress;
 | 
						|
  UINTN               NumPages;
 | 
						|
  UINT64              Attributes;
 | 
						|
} UNCACHED_ALLOCATION;
 | 
						|
 | 
						|
STATIC EFI_CPU_ARCH_PROTOCOL      *mCpu;
 | 
						|
STATIC LIST_ENTRY                 UncachedAllocationList;
 | 
						|
 | 
						|
STATIC
 | 
						|
PHYSICAL_ADDRESS
 | 
						|
HostToDeviceAddress (
 | 
						|
  IN  VOID      *Address
 | 
						|
  )
 | 
						|
{
 | 
						|
  return (PHYSICAL_ADDRESS)(UINTN)Address + PcdGet64 (PcdDmaDeviceOffset);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Provides the DMA controller-specific addresses needed to access system memory.
 | 
						|
 | 
						|
  Operation is relative to the DMA bus master.
 | 
						|
 | 
						|
  @param  Operation             Indicates if the bus master is going to read or
 | 
						|
                                write to system memory.
 | 
						|
  @param  HostAddress           The system memory address to map to the DMA
 | 
						|
                                controller.
 | 
						|
  @param  NumberOfBytes         On input the number of bytes to map. On output
 | 
						|
                                the number of bytes that were mapped.
 | 
						|
  @param  DeviceAddress         The resulting map address for the bus master
 | 
						|
                                controller to use to access the host's
 | 
						|
                                HostAddress.
 | 
						|
  @param  Mapping               A resulting value to pass to Unmap().
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The range was mapped for the returned
 | 
						|
                                NumberOfBytes.
 | 
						|
  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common
 | 
						|
                                buffer.
 | 
						|
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack
 | 
						|
                                of resources.
 | 
						|
  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested
 | 
						|
                                address.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
DmaMap (
 | 
						|
  IN     DMA_MAP_OPERATION              Operation,
 | 
						|
  IN     VOID                           *HostAddress,
 | 
						|
  IN OUT UINTN                          *NumberOfBytes,
 | 
						|
  OUT    PHYSICAL_ADDRESS               *DeviceAddress,
 | 
						|
  OUT    VOID                           **Mapping
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                      Status;
 | 
						|
  MAP_INFO_INSTANCE               *Map;
 | 
						|
  VOID                            *Buffer;
 | 
						|
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
 | 
						|
  UINTN                           AllocSize;
 | 
						|
 | 
						|
  if (HostAddress == NULL ||
 | 
						|
      NumberOfBytes == NULL ||
 | 
						|
      DeviceAddress == NULL ||
 | 
						|
      Mapping == NULL ) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Operation >= MapOperationMaximum) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  *DeviceAddress = HostToDeviceAddress (HostAddress);
 | 
						|
 | 
						|
  // Remember range so we can flush on the other side
 | 
						|
  Map = AllocatePool (sizeof (MAP_INFO_INSTANCE));
 | 
						|
  if (Map == NULL) {
 | 
						|
    return  EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Operation != MapOperationBusMasterRead &&
 | 
						|
      ((((UINTN)HostAddress & (mCpu->DmaBufferAlignment - 1)) != 0) ||
 | 
						|
       ((*NumberOfBytes & (mCpu->DmaBufferAlignment - 1)) != 0))) {
 | 
						|
 | 
						|
    // Get the cacheability of the region
 | 
						|
    Status = gDS->GetMemorySpaceDescriptor ((UINTN)HostAddress, &GcdDescriptor);
 | 
						|
    if (EFI_ERROR(Status)) {
 | 
						|
      goto FreeMapInfo;
 | 
						|
    }
 | 
						|
 | 
						|
    // If the mapped buffer is not an uncached buffer
 | 
						|
    if ((GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) != 0) {
 | 
						|
      //
 | 
						|
      // Operations of type MapOperationBusMasterCommonBuffer are only allowed
 | 
						|
      // on uncached buffers.
 | 
						|
      //
 | 
						|
      if (Operation == MapOperationBusMasterCommonBuffer) {
 | 
						|
        DEBUG ((DEBUG_ERROR,
 | 
						|
          "%a: Operation type 'MapOperationBusMasterCommonBuffer' is only "
 | 
						|
          "supported\non 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 a suitably aligned allocation that allows us to invalidate the
 | 
						|
      // cache without running the risk of corrupting adjacent unrelated data.
 | 
						|
      // Note that pool allocations are guaranteed to be 8 byte aligned, so
 | 
						|
      // we only have to add (alignment - 8) worth of padding.
 | 
						|
      //
 | 
						|
      Map->DoubleBuffer = TRUE;
 | 
						|
      AllocSize = ALIGN_VALUE (*NumberOfBytes, mCpu->DmaBufferAlignment) +
 | 
						|
                  (mCpu->DmaBufferAlignment - 8);
 | 
						|
      Map->BufferAddress = AllocatePool (AllocSize);
 | 
						|
      if (Map->BufferAddress == NULL) {
 | 
						|
        Status = EFI_OUT_OF_RESOURCES;
 | 
						|
        goto FreeMapInfo;
 | 
						|
      }
 | 
						|
 | 
						|
      Buffer = ALIGN_POINTER (Map->BufferAddress, mCpu->DmaBufferAlignment);
 | 
						|
      *DeviceAddress = HostToDeviceAddress (Buffer);
 | 
						|
 | 
						|
      //
 | 
						|
      // Get rid of any dirty cachelines covering the double buffer. This
 | 
						|
      // prevents them from being written back unexpectedly, potentially
 | 
						|
      // overwriting the data we receive from the device.
 | 
						|
      //
 | 
						|
      mCpu->FlushDataCache (mCpu, (UINTN)Buffer, *NumberOfBytes,
 | 
						|
              EfiCpuFlushTypeWriteBack);
 | 
						|
    } else {
 | 
						|
      Map->DoubleBuffer  = FALSE;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    Map->DoubleBuffer  = FALSE;
 | 
						|
 | 
						|
    DEBUG_CODE_BEGIN ();
 | 
						|
 | 
						|
    //
 | 
						|
    // 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 ((UINTN)HostAddress, &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, (UINTN)HostAddress, *NumberOfBytes,
 | 
						|
            EfiCpuFlushTypeWriteBackInvalidate);
 | 
						|
  }
 | 
						|
 | 
						|
  Map->HostAddress   = (UINTN)HostAddress;
 | 
						|
  Map->NumberOfBytes = *NumberOfBytes;
 | 
						|
  Map->Operation     = Operation;
 | 
						|
 | 
						|
  *Mapping = Map;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
FreeMapInfo:
 | 
						|
  FreePool (Map);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Completes the DmaMapBusMasterRead(), DmaMapBusMasterWrite(), or
 | 
						|
  DmaMapBusMasterCommonBuffer() operation and releases any corresponding
 | 
						|
  resources.
 | 
						|
 | 
						|
  @param  Mapping               The mapping value returned from 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
 | 
						|
EFIAPI
 | 
						|
DmaUnmap (
 | 
						|
  IN  VOID                         *Mapping
 | 
						|
  )
 | 
						|
{
 | 
						|
  MAP_INFO_INSTANCE *Map;
 | 
						|
  EFI_STATUS        Status;
 | 
						|
  VOID              *Buffer;
 | 
						|
 | 
						|
  if (Mapping == NULL) {
 | 
						|
    ASSERT (FALSE);
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Map = (MAP_INFO_INSTANCE *)Mapping;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  if (Map->DoubleBuffer) {
 | 
						|
    ASSERT (Map->Operation == MapOperationBusMasterWrite);
 | 
						|
 | 
						|
    if (Map->Operation != MapOperationBusMasterWrite) {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
    } else {
 | 
						|
      Buffer = ALIGN_POINTER (Map->BufferAddress, mCpu->DmaBufferAlignment);
 | 
						|
 | 
						|
      mCpu->FlushDataCache (mCpu, (UINTN)Buffer, Map->NumberOfBytes,
 | 
						|
              EfiCpuFlushTypeInvalidate);
 | 
						|
 | 
						|
      CopyMem ((VOID *)(UINTN)Map->HostAddress, Buffer, Map->NumberOfBytes);
 | 
						|
 | 
						|
      FreePool (Map->BufferAddress);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    if (Map->Operation == MapOperationBusMasterWrite) {
 | 
						|
      //
 | 
						|
      // Make sure we read buffer from uncached memory and not the cache
 | 
						|
      //
 | 
						|
      mCpu->FlushDataCache (mCpu, Map->HostAddress, Map->NumberOfBytes,
 | 
						|
              EfiCpuFlushTypeInvalidate);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (Map);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Allocates pages that are suitable for an DmaMap() of type
 | 
						|
  MapOperationBusMasterCommonBuffer mapping.
 | 
						|
 | 
						|
  @param  MemoryType            The type of memory to allocate,
 | 
						|
                                EfiBootServicesData or EfiRuntimeServicesData.
 | 
						|
  @param  Pages                 The number of pages to allocate.
 | 
						|
  @param  HostAddress           A pointer to store the base system memory
 | 
						|
                                address of the allocated range.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The requested memory pages were allocated.
 | 
						|
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
DmaAllocateBuffer (
 | 
						|
  IN  EFI_MEMORY_TYPE              MemoryType,
 | 
						|
  IN  UINTN                        Pages,
 | 
						|
  OUT VOID                         **HostAddress
 | 
						|
  )
 | 
						|
{
 | 
						|
  return DmaAllocateAlignedBuffer (MemoryType, Pages, 0, HostAddress);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Allocates pages that are suitable for an DmaMap() of type
 | 
						|
  MapOperationBusMasterCommonBuffer mapping, at the requested alignment.
 | 
						|
 | 
						|
  @param  MemoryType            The type of memory to allocate,
 | 
						|
                                EfiBootServicesData or EfiRuntimeServicesData.
 | 
						|
  @param  Pages                 The number of pages to allocate.
 | 
						|
  @param  Alignment             Alignment in bytes of the base of the returned
 | 
						|
                                buffer (must be a power of 2)
 | 
						|
  @param  HostAddress           A pointer to store the base system memory
 | 
						|
                                address of the allocated range.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The requested memory pages were allocated.
 | 
						|
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
DmaAllocateAlignedBuffer (
 | 
						|
  IN  EFI_MEMORY_TYPE              MemoryType,
 | 
						|
  IN  UINTN                        Pages,
 | 
						|
  IN  UINTN                        Alignment,
 | 
						|
  OUT VOID                         **HostAddress
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR   GcdDescriptor;
 | 
						|
  VOID                              *Allocation;
 | 
						|
  UINT64                            MemType;
 | 
						|
  UNCACHED_ALLOCATION               *Alloc;
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
 | 
						|
  if (Alignment == 0) {
 | 
						|
    Alignment = EFI_PAGE_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (HostAddress == NULL ||
 | 
						|
      (Alignment & (Alignment - 1)) != 0) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (MemoryType == EfiBootServicesData) {
 | 
						|
    Allocation = AllocateAlignedPages (Pages, Alignment);
 | 
						|
  } else if (MemoryType == EfiRuntimeServicesData) {
 | 
						|
    Allocation = AllocateAlignedRuntimePages (Pages, Alignment);
 | 
						|
  } else {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Allocation == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  // Get the cacheability of the region
 | 
						|
  Status = gDS->GetMemorySpaceDescriptor ((UINTN)Allocation, &GcdDescriptor);
 | 
						|
  if (EFI_ERROR(Status)) {
 | 
						|
    goto FreeBuffer;
 | 
						|
  }
 | 
						|
 | 
						|
  // Choose a suitable uncached memory type that is supported by the region
 | 
						|
  if (GcdDescriptor.Capabilities & EFI_MEMORY_WC) {
 | 
						|
    MemType = EFI_MEMORY_WC;
 | 
						|
  } else if (GcdDescriptor.Capabilities & EFI_MEMORY_UC) {
 | 
						|
    MemType = EFI_MEMORY_UC;
 | 
						|
  } else {
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
    goto FreeBuffer;
 | 
						|
  }
 | 
						|
 | 
						|
  Alloc = AllocatePool (sizeof *Alloc);
 | 
						|
  if (Alloc == NULL) {
 | 
						|
    goto FreeBuffer;
 | 
						|
  }
 | 
						|
 | 
						|
  Alloc->HostAddress = Allocation;
 | 
						|
  Alloc->NumPages = Pages;
 | 
						|
  Alloc->Attributes = GcdDescriptor.Attributes;
 | 
						|
 | 
						|
  InsertHeadList (&UncachedAllocationList, &Alloc->Link);
 | 
						|
 | 
						|
  // Remap the region with the new attributes
 | 
						|
  Status = gDS->SetMemorySpaceAttributes ((PHYSICAL_ADDRESS)(UINTN)Allocation,
 | 
						|
                                          EFI_PAGES_TO_SIZE (Pages),
 | 
						|
                                          MemType);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto FreeAlloc;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = mCpu->FlushDataCache (mCpu,
 | 
						|
                                 (PHYSICAL_ADDRESS)(UINTN)Allocation,
 | 
						|
                                 EFI_PAGES_TO_SIZE (Pages),
 | 
						|
                                 EfiCpuFlushTypeInvalidate);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto FreeAlloc;
 | 
						|
  }
 | 
						|
 | 
						|
  *HostAddress = Allocation;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
FreeAlloc:
 | 
						|
  RemoveEntryList (&Alloc->Link);
 | 
						|
  FreePool (Alloc);
 | 
						|
 | 
						|
FreeBuffer:
 | 
						|
  FreePages (Allocation, Pages);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Frees memory that was allocated with DmaAllocateBuffer().
 | 
						|
 | 
						|
  @param  Pages                 The number of pages to free.
 | 
						|
  @param  HostAddress           The base system memory address of the allocated
 | 
						|
                                range.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The requested memory pages were freed.
 | 
						|
  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and
 | 
						|
                                Pages was not allocated with
 | 
						|
                                DmaAllocateBuffer().
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
DmaFreeBuffer (
 | 
						|
  IN  UINTN                        Pages,
 | 
						|
  IN  VOID                         *HostAddress
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY                       *Link;
 | 
						|
  UNCACHED_ALLOCATION              *Alloc;
 | 
						|
  BOOLEAN                          Found;
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
 | 
						|
  if (HostAddress == NULL) {
 | 
						|
     return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Link = GetFirstNode (&UncachedAllocationList), Found = FALSE;
 | 
						|
       !IsNull (&UncachedAllocationList, Link);
 | 
						|
       Link = GetNextNode (&UncachedAllocationList, Link)) {
 | 
						|
 | 
						|
    Alloc = BASE_CR (Link, UNCACHED_ALLOCATION, Link);
 | 
						|
    if (Alloc->HostAddress == HostAddress && Alloc->NumPages == Pages) {
 | 
						|
      Found = TRUE;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!Found) {
 | 
						|
    ASSERT (FALSE);
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  RemoveEntryList (&Alloc->Link);
 | 
						|
 | 
						|
  Status = gDS->SetMemorySpaceAttributes ((PHYSICAL_ADDRESS)(UINTN)HostAddress,
 | 
						|
                                          EFI_PAGES_TO_SIZE (Pages),
 | 
						|
                                          Alloc->Attributes);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto FreeAlloc;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If we fail to restore the original attributes, it is better to leak the
 | 
						|
  // memory than to return it to the heap
 | 
						|
  //
 | 
						|
  FreePages (HostAddress, Pages);
 | 
						|
 | 
						|
FreeAlloc:
 | 
						|
  FreePool (Alloc);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
NonCoherentDmaLibConstructor (
 | 
						|
  IN EFI_HANDLE       ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  InitializeListHead (&UncachedAllocationList);
 | 
						|
 | 
						|
  // Get the Cpu protocol for later use
 | 
						|
  return gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu);
 | 
						|
}
 |