diff --git a/dma.h b/dma.h
index 2bdc236..ce6aab2 100644
--- a/dma.h
+++ b/dma.h
@@ -18,9 +18,15 @@
 typedef struct ScatterGatherEntry ScatterGatherEntry;
 
 #if defined(TARGET_PHYS_ADDR_BITS)
+typedef target_phys_addr_t dma_addr_t;
+typedef enum {
+    DMA_DIRECTION_TO_DEVICE = 0,
+    DMA_DIRECTION_FROM_DEVICE = 1,
+} DMADirection;
+
 struct ScatterGatherEntry {
-    target_phys_addr_t base;
-    target_phys_addr_t len;
+    dma_addr_t base;
+    dma_addr_t len;
 };
 
 struct QEMUSGList {
@@ -31,8 +37,7 @@ struct QEMUSGList {
 };
 
 void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint);
-void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
-                     target_phys_addr_t len);
+void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len);
 void qemu_sglist_destroy(QEMUSGList *qsg);
 #endif
 
diff --git a/hw/pci.c b/hw/pci.c
index 749e8d8..4dbdd81 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -2129,3 +2129,56 @@ MemoryRegion *pci_address_space_io(PCIDevice *dev)
 {
     return dev->bus->address_space_io;
 }
+
+#define PCI_DMA_DEFINE_LDST(_lname, _sname, _end, _bits)                  \
+    uint##_bits##_t ld##_lname##_##_end##_pci_dma(PCIDevice *dev,         \
+                                                  dma_addr_t addr)        \
+    {                                                                     \
+        uint##_bits##_t val;                                              \
+        pci_dma_read(dev, addr, &val, sizeof(val));                       \
+        return _end##_bits##_to_cpu(val);                                 \
+    }                                                                     \
+    void st##_sname##_##_end##_pci_dma(PCIDevice *dev,                    \
+                              dma_addr_t addr, uint##_bits##_t val)       \
+    {                                                                     \
+        val = cpu_to_##_end##_bits(val);                                  \
+        pci_dma_write(dev, addr, &val, sizeof(val));                      \
+    }
+
+uint8_t ldub_pci_dma(PCIDevice *dev, dma_addr_t addr)
+{
+    uint8_t val;
+
+    pci_dma_read(dev, addr, &val, sizeof(val));
+    return val;
+}
+
+void stb_pci_dma(PCIDevice *dev, dma_addr_t addr, uint8_t val)
+{
+    pci_dma_write(dev, addr, &val, sizeof(val));
+}
+
+PCI_DMA_DEFINE_LDST(uw, w, le, 16);
+PCI_DMA_DEFINE_LDST(uw, w, be, 16);
+PCI_DMA_DEFINE_LDST(l, l, le, 32);
+PCI_DMA_DEFINE_LDST(l, l, be, 32);
+PCI_DMA_DEFINE_LDST(q, q, le, 64);
+PCI_DMA_DEFINE_LDST(q, q, be, 64);
+
+void *pci_dma_map(PCIDevice *dev, dma_addr_t addr, dma_addr_t *plen,
+                  DMADirection dir)
+{
+    target_phys_addr_t len = *plen;
+    void *buf;
+
+    buf = cpu_physical_memory_map(addr, &len, dir == DMA_DIRECTION_FROM_DEVICE);
+    *plen = len;
+    return buf;
+}
+
+void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len,
+                   DMADirection dir, dma_addr_t access_len)
+{
+    cpu_physical_memory_unmap(buffer, len, dir == DMA_DIRECTION_FROM_DEVICE,
+                              access_len);
+}
diff --git a/hw/pci.h b/hw/pci.h
index 86a81c8..0f89d57 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -6,6 +6,7 @@
 
 #include "qdev.h"
 #include "memory.h"
+#include "dma.h"
 
 /* PCI includes legacy ISA access.  */
 #include "isa.h"
@@ -487,4 +488,52 @@ static inline uint32_t pci_config_size(const PCIDevice *d)
     return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE;
 }
 
+/* DMA access functions */
+static inline int pci_dma_rw(PCIDevice *dev, dma_addr_t addr,
+                             void *buf, dma_addr_t len, DMADirection dir)
+{
+    cpu_physical_memory_rw(addr, buf, len, dir == DMA_DIRECTION_FROM_DEVICE);
+    return 0;
+}
+
+static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr,
+                               void *buf, dma_addr_t len)
+{
+    return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE);
+}
+
+static inline int pci_dma_write(PCIDevice *dev, dma_addr_t addr,
+                                const void *buf, dma_addr_t len)
+{
+    return pci_dma_rw(dev, addr, (void *) buf, len, DMA_DIRECTION_FROM_DEVICE);
+}
+
+#define PCI_DMA_DECLARE_LDST(_lname, _sname, _bits)                           \
+    uint##_bits##_t ld##_lname##_le_pci_dma(PCIDevice *dev, dma_addr_t addr); \
+    void st##_sname##_le_pci_dma(PCIDevice *dev, dma_addr_t addr,             \
+                                 uint##_bits##_t val);                        \
+    uint##_bits##_t ld##_lname##_be_pci_dma(PCIDevice *dev, dma_addr_t addr); \
+    void st##_sname##_be_pci_dma(PCIDevice *dev, dma_addr_t addr,             \
+                                 uint##_bits##_t val);
+
+uint8_t ldub_pci_dma(PCIDevice *dev, dma_addr_t addr);
+void stb_pci_dma(PCIDevice *dev, dma_addr_t addr, uint8_t val);
+
+PCI_DMA_DECLARE_LDST(uw, w, 16);
+PCI_DMA_DECLARE_LDST(l, l, 32);
+PCI_DMA_DECLARE_LDST(q, q, 64);
+
+#undef DECLARE_LDST_DMA
+
+void *pci_dma_map(PCIDevice *dev, dma_addr_t addr, dma_addr_t *plen,
+                  DMADirection dir);
+void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len,
+                   DMADirection dir, dma_addr_t access_len);
+
+static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev,
+                                       int alloc_hint)
+{
+    qemu_sglist_init(qsg, alloc_hint);
+}
+
 #endif
