]> git.proxmox.com Git - mirror_edk2.git/commitdiff
EmbeddedPkg: implement NonCoherentDmaLib based on ArmDmaLib
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Wed, 30 Aug 2017 07:21:59 +0000 (08:21 +0100)
committerArd Biesheuvel <ard.biesheuvel@linaro.org>
Wed, 30 Aug 2017 13:13:30 +0000 (14:13 +0100)
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>
EmbeddedPkg/EmbeddedPkg.dsc
EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c [new file with mode: 0644]
EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf [new file with mode: 0644]

index 4f0a3438e13431fac7f952e6c0507ad672135d5e..d7ee6a3018bfbc25be309af44da9be27b68c73db 100644 (file)
   EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf\r
   EmbeddedPkg/Library/LzmaHobCustomDecompressLib/LzmaHobCustomDecompressLib.inf\r
   EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.inf\r
+  EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf\r
   EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.inf\r
 \r
   EmbeddedPkg/Ebl/Ebl.inf\r
diff --git a/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c b/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c
new file mode 100644 (file)
index 0000000..08b9c01
--- /dev/null
@@ -0,0 +1,491 @@
+/** @file\r
+\r
+  Generic non-coherent implementation of DmaLib.h\r
+\r
+  Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
+  Copyright (c) 2015 - 2017, Linaro, Ltd. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials are licensed and made\r
+  available under the terms and conditions of the BSD License which\r
+  accompanies this distribution.  The full text of the license may be\r
+  found at http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR\r
+  IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DmaLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+\r
+#include <Protocol/Cpu.h>\r
+\r
+typedef struct {\r
+  EFI_PHYSICAL_ADDRESS      HostAddress;\r
+  VOID                      *BufferAddress;\r
+  UINTN                     NumberOfBytes;\r
+  DMA_MAP_OPERATION         Operation;\r
+  BOOLEAN                   DoubleBuffer;\r
+} MAP_INFO_INSTANCE;\r
+\r
+\r
+typedef struct {\r
+  LIST_ENTRY          Link;\r
+  VOID                *HostAddress;\r
+  UINTN               NumPages;\r
+  UINT64              Attributes;\r
+} UNCACHED_ALLOCATION;\r
+\r
+STATIC EFI_CPU_ARCH_PROTOCOL      *mCpu;\r
+STATIC LIST_ENTRY                 UncachedAllocationList;\r
+\r
+STATIC\r
+PHYSICAL_ADDRESS\r
+HostToDeviceAddress (\r
+  IN  VOID      *Address\r
+  )\r
+{\r
+  return (PHYSICAL_ADDRESS)(UINTN)Address + PcdGet64 (PcdDmaDeviceOffset);\r
+}\r
+\r
+/**\r
+  Provides the DMA controller-specific addresses needed to access system memory.\r
+\r
+  Operation is relative to the DMA bus master.\r
+\r
+  @param  Operation             Indicates if the bus master is going to read or\r
+                                write to system memory.\r
+  @param  HostAddress           The system memory address to map to the DMA\r
+                                controller.\r
+  @param  NumberOfBytes         On input the number of bytes to map. On output\r
+                                the number of bytes that were mapped.\r
+  @param  DeviceAddress         The resulting map address for the bus master\r
+                                controller to use to access the host's\r
+                                HostAddress.\r
+  @param  Mapping               A resulting value to pass to Unmap().\r
+\r
+  @retval EFI_SUCCESS           The range was mapped for the returned\r
+                                NumberOfBytes.\r
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common\r
+                                buffer.\r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack\r
+                                of resources.\r
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested\r
+                                address.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DmaMap (\r
+  IN     DMA_MAP_OPERATION              Operation,\r
+  IN     VOID                           *HostAddress,\r
+  IN OUT UINTN                          *NumberOfBytes,\r
+  OUT    PHYSICAL_ADDRESS               *DeviceAddress,\r
+  OUT    VOID                           **Mapping\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  MAP_INFO_INSTANCE               *Map;\r
+  VOID                            *Buffer;\r
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
+  UINTN                           AllocSize;\r
+\r
+  if (HostAddress == NULL ||\r
+      NumberOfBytes == NULL ||\r
+      DeviceAddress == NULL ||\r
+      Mapping == NULL ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Operation >= MapOperationMaximum) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *DeviceAddress = HostToDeviceAddress (HostAddress);\r
+\r
+  // Remember range so we can flush on the other side\r
+  Map = AllocatePool (sizeof (MAP_INFO_INSTANCE));\r
+  if (Map == NULL) {\r
+    return  EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (Operation != MapOperationBusMasterRead &&\r
+      ((((UINTN)HostAddress & (mCpu->DmaBufferAlignment - 1)) != 0) ||\r
+       ((*NumberOfBytes & (mCpu->DmaBufferAlignment - 1)) != 0))) {\r
+\r
+    // Get the cacheability of the region\r
+    Status = gDS->GetMemorySpaceDescriptor ((UINTN)HostAddress, &GcdDescriptor);\r
+    if (EFI_ERROR(Status)) {\r
+      goto FreeMapInfo;\r
+    }\r
+\r
+    // If the mapped buffer is not an uncached buffer\r
+    if ((GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) != 0) {\r
+      //\r
+      // Operations of type MapOperationBusMasterCommonBuffer are only allowed\r
+      // on uncached buffers.\r
+      //\r
+      if (Operation == MapOperationBusMasterCommonBuffer) {\r
+        DEBUG ((DEBUG_ERROR,\r
+          "%a: Operation type 'MapOperationBusMasterCommonBuffer' is only "\r
+          "supported\non memory regions that were allocated using "\r
+          "DmaAllocateBuffer ()\n", __FUNCTION__));\r
+        Status = EFI_UNSUPPORTED;\r
+        goto FreeMapInfo;\r
+      }\r
+\r
+      //\r
+      // If the buffer does not fill entire cache lines we must double buffer\r
+      // into a suitably aligned allocation that allows us to invalidate the\r
+      // cache without running the risk of corrupting adjacent unrelated data.\r
+      // Note that pool allocations are guaranteed to be 8 byte aligned, so\r
+      // we only have to add (alignment - 8) worth of padding.\r
+      //\r
+      Map->DoubleBuffer = TRUE;\r
+      AllocSize = ALIGN_VALUE (*NumberOfBytes, mCpu->DmaBufferAlignment) +\r
+                  (mCpu->DmaBufferAlignment - 8);\r
+      Map->BufferAddress = AllocatePool (AllocSize);\r
+      if (Map->BufferAddress == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto FreeMapInfo;\r
+      }\r
+\r
+      Buffer = ALIGN_POINTER (Map->BufferAddress, mCpu->DmaBufferAlignment);\r
+      *DeviceAddress = HostToDeviceAddress (Buffer);\r
+\r
+      //\r
+      // Get rid of any dirty cachelines covering the double buffer. This\r
+      // prevents them from being written back unexpectedly, potentially\r
+      // overwriting the data we receive from the device.\r
+      //\r
+      mCpu->FlushDataCache (mCpu, (UINTN)Buffer, *NumberOfBytes,\r
+              EfiCpuFlushTypeWriteBack);\r
+    } else {\r
+      Map->DoubleBuffer  = FALSE;\r
+    }\r
+  } else {\r
+    Map->DoubleBuffer  = FALSE;\r
+\r
+    DEBUG_CODE_BEGIN ();\r
+\r
+    //\r
+    // The operation type check above only executes if the buffer happens to be\r
+    // misaligned with respect to CWG, but even if it is aligned, we should not\r
+    // allow arbitrary buffers to be used for creating consistent mappings.\r
+    // So duplicate the check here when running in DEBUG mode, just to assert\r
+    // that we are not trying to create a consistent mapping for cached memory.\r
+    //\r
+    Status = gDS->GetMemorySpaceDescriptor ((UINTN)HostAddress, &GcdDescriptor);\r
+    ASSERT_EFI_ERROR(Status);\r
+\r
+    ASSERT (Operation != MapOperationBusMasterCommonBuffer ||\r
+            (GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) == 0);\r
+\r
+    DEBUG_CODE_END ();\r
+\r
+    // Flush the Data Cache (should not have any effect if the memory region is\r
+    // uncached)\r
+    mCpu->FlushDataCache (mCpu, (UINTN)HostAddress, *NumberOfBytes,\r
+            EfiCpuFlushTypeWriteBackInvalidate);\r
+  }\r
+\r
+  Map->HostAddress   = (UINTN)HostAddress;\r
+  Map->NumberOfBytes = *NumberOfBytes;\r
+  Map->Operation     = Operation;\r
+\r
+  *Mapping = Map;\r
+\r
+  return EFI_SUCCESS;\r
+\r
+FreeMapInfo:\r
+  FreePool (Map);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Completes the DmaMapBusMasterRead(), DmaMapBusMasterWrite(), or\r
+  DmaMapBusMasterCommonBuffer() operation and releases any corresponding\r
+  resources.\r
+\r
+  @param  Mapping               The mapping value returned from DmaMap*().\r
+\r
+  @retval EFI_SUCCESS           The range was unmapped.\r
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system\r
+                                memory.\r
+  @retval EFI_INVALID_PARAMETER An inconsistency was detected between the\r
+                                mapping type and the DoubleBuffer field\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DmaUnmap (\r
+  IN  VOID                         *Mapping\r
+  )\r
+{\r
+  MAP_INFO_INSTANCE *Map;\r
+  EFI_STATUS        Status;\r
+  VOID              *Buffer;\r
+\r
+  if (Mapping == NULL) {\r
+    ASSERT (FALSE);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Map = (MAP_INFO_INSTANCE *)Mapping;\r
+\r
+  Status = EFI_SUCCESS;\r
+  if (Map->DoubleBuffer) {\r
+    ASSERT (Map->Operation == MapOperationBusMasterWrite);\r
+\r
+    if (Map->Operation != MapOperationBusMasterWrite) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+    } else {\r
+      Buffer = ALIGN_POINTER (Map->BufferAddress, mCpu->DmaBufferAlignment);\r
+\r
+      mCpu->FlushDataCache (mCpu, (UINTN)Buffer, Map->NumberOfBytes,\r
+              EfiCpuFlushTypeInvalidate);\r
+\r
+      CopyMem ((VOID *)(UINTN)Map->HostAddress, Buffer, Map->NumberOfBytes);\r
+\r
+      FreePool (Map->BufferAddress);\r
+    }\r
+  } else {\r
+    if (Map->Operation == MapOperationBusMasterWrite) {\r
+      //\r
+      // Make sure we read buffer from uncached memory and not the cache\r
+      //\r
+      mCpu->FlushDataCache (mCpu, Map->HostAddress, Map->NumberOfBytes,\r
+              EfiCpuFlushTypeInvalidate);\r
+    }\r
+  }\r
+\r
+  FreePool (Map);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Allocates pages that are suitable for an DmaMap() of type\r
+  MapOperationBusMasterCommonBuffer mapping.\r
+\r
+  @param  MemoryType            The type of memory to allocate,\r
+                                EfiBootServicesData or EfiRuntimeServicesData.\r
+  @param  Pages                 The number of pages to allocate.\r
+  @param  HostAddress           A pointer to store the base system memory\r
+                                address of the allocated range.\r
+\r
+  @retval EFI_SUCCESS           The requested memory pages were allocated.\r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DmaAllocateBuffer (\r
+  IN  EFI_MEMORY_TYPE              MemoryType,\r
+  IN  UINTN                        Pages,\r
+  OUT VOID                         **HostAddress\r
+  )\r
+{\r
+  return DmaAllocateAlignedBuffer (MemoryType, Pages, 0, HostAddress);\r
+}\r
+\r
+/**\r
+  Allocates pages that are suitable for an DmaMap() of type\r
+  MapOperationBusMasterCommonBuffer mapping, at the requested alignment.\r
+\r
+  @param  MemoryType            The type of memory to allocate,\r
+                                EfiBootServicesData or EfiRuntimeServicesData.\r
+  @param  Pages                 The number of pages to allocate.\r
+  @param  Alignment             Alignment in bytes of the base of the returned\r
+                                buffer (must be a power of 2)\r
+  @param  HostAddress           A pointer to store the base system memory\r
+                                address of the allocated range.\r
+\r
+  @retval EFI_SUCCESS           The requested memory pages were allocated.\r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DmaAllocateAlignedBuffer (\r
+  IN  EFI_MEMORY_TYPE              MemoryType,\r
+  IN  UINTN                        Pages,\r
+  IN  UINTN                        Alignment,\r
+  OUT VOID                         **HostAddress\r
+  )\r
+{\r
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR   GcdDescriptor;\r
+  VOID                              *Allocation;\r
+  UINT64                            MemType;\r
+  UNCACHED_ALLOCATION               *Alloc;\r
+  EFI_STATUS                        Status;\r
+\r
+  if (Alignment == 0) {\r
+    Alignment = EFI_PAGE_SIZE;\r
+  }\r
+\r
+  if (HostAddress == NULL ||\r
+      (Alignment & (Alignment - 1)) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (MemoryType == EfiBootServicesData) {\r
+    Allocation = AllocateAlignedPages (Pages, Alignment);\r
+  } else if (MemoryType == EfiRuntimeServicesData) {\r
+    Allocation = AllocateAlignedRuntimePages (Pages, Alignment);\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Allocation == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  // Get the cacheability of the region\r
+  Status = gDS->GetMemorySpaceDescriptor ((UINTN)Allocation, &GcdDescriptor);\r
+  if (EFI_ERROR(Status)) {\r
+    goto FreeBuffer;\r
+  }\r
+\r
+  // Choose a suitable uncached memory type that is supported by the region\r
+  if (GcdDescriptor.Capabilities & EFI_MEMORY_WC) {\r
+    MemType = EFI_MEMORY_WC;\r
+  } else if (GcdDescriptor.Capabilities & EFI_MEMORY_UC) {\r
+    MemType = EFI_MEMORY_UC;\r
+  } else {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto FreeBuffer;\r
+  }\r
+\r
+  Alloc = AllocatePool (sizeof *Alloc);\r
+  if (Alloc == NULL) {\r
+    goto FreeBuffer;\r
+  }\r
+\r
+  Alloc->HostAddress = Allocation;\r
+  Alloc->NumPages = Pages;\r
+  Alloc->Attributes = GcdDescriptor.Attributes;\r
+\r
+  InsertHeadList (&UncachedAllocationList, &Alloc->Link);\r
+\r
+  // Remap the region with the new attributes\r
+  Status = gDS->SetMemorySpaceAttributes ((PHYSICAL_ADDRESS)(UINTN)Allocation,\r
+                                          EFI_PAGES_TO_SIZE (Pages),\r
+                                          MemType);\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeAlloc;\r
+  }\r
+\r
+  Status = mCpu->FlushDataCache (mCpu,\r
+                                 (PHYSICAL_ADDRESS)(UINTN)Allocation,\r
+                                 EFI_PAGES_TO_SIZE (Pages),\r
+                                 EfiCpuFlushTypeInvalidate);\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeAlloc;\r
+  }\r
+\r
+  *HostAddress = Allocation;\r
+\r
+  return EFI_SUCCESS;\r
+\r
+FreeAlloc:\r
+  RemoveEntryList (&Alloc->Link);\r
+  FreePool (Alloc);\r
+\r
+FreeBuffer:\r
+  FreePages (Allocation, Pages);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Frees memory that was allocated with DmaAllocateBuffer().\r
+\r
+  @param  Pages                 The number of pages to free.\r
+  @param  HostAddress           The base system memory address of the allocated\r
+                                range.\r
+\r
+  @retval EFI_SUCCESS           The requested memory pages were freed.\r
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and\r
+                                Pages was not allocated with\r
+                                DmaAllocateBuffer().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DmaFreeBuffer (\r
+  IN  UINTN                        Pages,\r
+  IN  VOID                         *HostAddress\r
+  )\r
+{\r
+  LIST_ENTRY                       *Link;\r
+  UNCACHED_ALLOCATION              *Alloc;\r
+  BOOLEAN                          Found;\r
+  EFI_STATUS                       Status;\r
+\r
+  if (HostAddress == NULL) {\r
+     return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  for (Link = GetFirstNode (&UncachedAllocationList), Found = FALSE;\r
+       !IsNull (&UncachedAllocationList, Link);\r
+       Link = GetNextNode (&UncachedAllocationList, Link)) {\r
+\r
+    Alloc = BASE_CR (Link, UNCACHED_ALLOCATION, Link);\r
+    if (Alloc->HostAddress == HostAddress && Alloc->NumPages == Pages) {\r
+      Found = TRUE;\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (!Found) {\r
+    ASSERT (FALSE);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  RemoveEntryList (&Alloc->Link);\r
+\r
+  Status = gDS->SetMemorySpaceAttributes ((PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
+                                          EFI_PAGES_TO_SIZE (Pages),\r
+                                          Alloc->Attributes);\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeAlloc;\r
+  }\r
+\r
+  //\r
+  // If we fail to restore the original attributes, it is better to leak the\r
+  // memory than to return it to the heap\r
+  //\r
+  FreePages (HostAddress, Pages);\r
+\r
+FreeAlloc:\r
+  FreePool (Alloc);\r
+  return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+NonCoherentDmaLibConstructor (\r
+  IN EFI_HANDLE       ImageHandle,\r
+  IN EFI_SYSTEM_TABLE *SystemTable\r
+  )\r
+{\r
+  InitializeListHead (&UncachedAllocationList);\r
+\r
+  // Get the Cpu protocol for later use\r
+  return gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu);\r
+}\r
diff --git a/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf b/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf
new file mode 100644 (file)
index 0000000..9f430d6
--- /dev/null
@@ -0,0 +1,50 @@
+#/** @file\r
+#\r
+#  Generic non-coherent implementation of DmaLib.h\r
+#\r
+#  Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
+#  Copyright (c) 2015 - 2017, Linaro, Ltd. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials are licensed and made\r
+#  available under the terms and conditions of the BSD License which\r
+#  accompanies this distribution.  The full text of the license may be\r
+#  found at http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR\r
+#  IMPLIED.\r
+#\r
+#**/\r
+\r
+[Defines]\r
+  INF_VERSION                 = 0x00010019\r
+  BASE_NAME                   = NonCoherentDmaLib\r
+  FILE_GUID                   = 43ad4920-db15-4e24-9889-2db568431fbd\r
+  MODULE_TYPE                 = DXE_DRIVER\r
+  VERSION_STRING              = 1.0\r
+  LIBRARY_CLASS               = DmaLib\r
+  CONSTRUCTOR                 = NonCoherentDmaLibConstructor\r
+\r
+[Sources]\r
+  NonCoherentDmaLib.c\r
+\r
+[Packages]\r
+  EmbeddedPkg/EmbeddedPkg.dec\r
+  MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseMemoryLib\r
+  DebugLib\r
+  DxeServicesTableLib\r
+  IoLib\r
+  MemoryAllocationLib\r
+  UefiBootServicesTableLib\r
+\r
+[Protocols]\r
+  gEfiCpuArchProtocolGuid\r
+\r
+[Pcd]\r
+  gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset\r
+\r
+[Depex]\r
+  gEfiCpuArchProtocolGuid\r