diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
index 5b162bf98739..6e87c625102e 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
@@ -30,4 +30,17 @@ InternalQemuFwCfgIsAvailable (
   VOID
   );
 
+
+/**
+  Returns a boolean indicating whether QEMU provides the DMA-like access method
+  for fw_cfg.
+
+  @retval    TRUE   The DMA-like access method is available.
+  @retval    FALSE  The DMA-like access method is unavailable.
+**/
+BOOLEAN
+InternalQemuFwCfgDmaIsAvailable (
+  VOID
+  );
+
 #endif
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
index 804d5b0e42be..f609f6422878 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
@@ -21,6 +21,7 @@
 #include <Library/QemuFwCfgLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/UefiBootServicesTableLib.h>
+#include <IndustryStandard/QemuFwCfgDma.h>
 
 #include "QemuFwCfgLibInternal.h"
 
@@ -99,6 +100,70 @@ QemuFwCfgSelectItem (
 
 
 /**
+  Transfer an array of bytes using the DMA interface.
+
+  @param[in]     Size    Size in bytes to transfer.
+  @param[in,out] Buffer  Buffer to read data into or write data from. May be
+                         NULL if Size is zero.
+  @param[in]     Write   TRUE if writing to fw_cfg from Buffer, FALSE if
+                         reading from fw_cfg into Buffer.
+**/
+VOID
+InternalQemuFwCfgDmaBytes (
+  IN     UINT32   Size,
+  IN OUT VOID     *Buffer OPTIONAL,
+  IN     BOOLEAN  Write
+  )
+{
+  volatile FW_CFG_DMA_ACCESS Access;
+  UINT32                     AccessHigh, AccessLow;
+  UINT32                     Status;
+
+  if (Size == 0) {
+    return;
+  }
+
+  Access.Control = SwapBytes32 (
+                    Write ? FW_CFG_DMA_CTL_WRITE : FW_CFG_DMA_CTL_READ
+                    );
+  Access.Length  = SwapBytes32 (Size);
+  Access.Address = SwapBytes64 ((UINTN)Buffer);
+
+  //
+  // Delimit the transfer from (a) modifications to Access, (b) in case of a
+  // write, from writes to Buffer by the caller.
+  //
+  MemoryFence ();
+
+  //
+  // Start the transfer.
+  //
+  AccessHigh = (UINT32)RShiftU64 ((UINTN)&Access, 32);
+  AccessLow  = (UINT32)(UINTN)&Access;
+  IoWrite32 (0x514, SwapBytes32 (AccessHigh));
+  IoWrite32 (0x518, SwapBytes32 (AccessLow));
+
+  //
+  // Don't look at Access.Control before starting the transfer.
+  //
+  MemoryFence ();
+
+  //
+  // Wait for the transfer to complete.
+  //
+  do {
+    Status = SwapBytes32 (Access.Control);
+    ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
+  } while (Status != 0);
+
+  //
+  // After a read, the caller will want to use Buffer.
+  //
+  MemoryFence ();
+}
+
+
+/**
   Reads firmware configuration bytes into a buffer
 
   @param[in] Size - Size in bytes to read
@@ -112,6 +177,10 @@ InternalQemuFwCfgReadBytes (
   IN VOID                   *Buffer  OPTIONAL
   )
 {
+  if (InternalQemuFwCfgDmaIsAvailable () && Size <= MAX_UINT32) {
+    InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FALSE);
+    return;
+  }
   IoReadFifo8 (0x511, Size, Buffer);
 }
 
@@ -160,6 +229,10 @@ QemuFwCfgWriteBytes (
   )
 {
   if (InternalQemuFwCfgIsAvailable ()) {
+    if (InternalQemuFwCfgDmaIsAvailable () && Size <= MAX_UINT32) {
+      InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, TRUE);
+      return;
+    }
     IoWriteFifo8 (0x511, Size, Buffer);
   }
 }
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiDxe.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiDxe.c
index 88d88c0edf69..fde4a11b4e0d 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiDxe.c
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiDxe.c
@@ -14,12 +14,14 @@
   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 **/
 
+#include <IndustryStandard/QemuFwCfgDma.h>
 #include <Library/DebugLib.h>
 #include <Library/QemuFwCfgLib.h>
 
 #include "QemuFwCfgLibInternal.h"
 
 STATIC BOOLEAN mQemuFwCfgSupported = FALSE;
+STATIC BOOLEAN mQemuFwCfgDmaSupported;
 
 
 /**
@@ -53,8 +55,10 @@ QemuFwCfgInitialize (
 
   //
   // Enable the access routines while probing to see if it is supported.
+  // For probing we always use the IO Port (IoReadFifo8()) access method.
   //
   mQemuFwCfgSupported = TRUE;
+  mQemuFwCfgDmaSupported = FALSE;
 
   QemuFwCfgSelectItem (QemuFwCfgItemSignature);
   Signature = QemuFwCfgRead32 ();
@@ -70,7 +74,12 @@ QemuFwCfgInitialize (
     return RETURN_SUCCESS;
   }
 
-  DEBUG ((EFI_D_INFO, "QemuFwCfg interface is supported.\n"));
+  if ((Revision & FW_CFG_F_DMA) == 0) {
+    DEBUG ((DEBUG_INFO, "QemuFwCfg interface (IO Port) is supported.\n"));
+  } else {
+    mQemuFwCfgDmaSupported = TRUE;
+    DEBUG ((DEBUG_INFO, "QemuFwCfg interface (DMA) is supported.\n"));
+  }
   return RETURN_SUCCESS;
 }
 
@@ -91,3 +100,18 @@ InternalQemuFwCfgIsAvailable (
 {
   return mQemuFwCfgSupported;
 }
+
+/**
+  Returns a boolean indicating whether QEMU provides the DMA-like access method
+  for fw_cfg.
+
+  @retval    TRUE   The DMA-like access method is available.
+  @retval    FALSE  The DMA-like access method is unavailable.
+**/
+BOOLEAN
+InternalQemuFwCfgDmaIsAvailable (
+  VOID
+  )
+{
+  return mQemuFwCfgDmaSupported;
+}
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c
index 56c59ca3f01d..465ccbe90dad 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c
@@ -79,3 +79,18 @@ InternalQemuFwCfgIsAvailable (
   //
   return TRUE;
 }
+
+/**
+  Returns a boolean indicating whether QEMU provides the DMA-like access method
+  for fw_cfg.
+
+  @retval    TRUE   The DMA-like access method is available.
+  @retval    FALSE  The DMA-like access method is unavailable.
+**/
+BOOLEAN
+InternalQemuFwCfgDmaIsAvailable (
+  VOID
+  )
+{
+  return FALSE;
+}
