diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index 3055dd2..f80e7b6 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -56,11 +56,15 @@ typedef struct IVShmemState {
 
     CharDriverState **eventfd_chr;
     CharDriverState *server_chr;
-    int ivshmem_mmio_io_addr;
+    MemoryRegion ivshmem_mmio;
 
     pcibus_t mmio_addr;
-    pcibus_t shm_pci_addr;
-    uint64_t ivshmem_offset;
+    /* We might need to register the BAR before we actually have the memory.
+     * So prepare a container MemoryRegion for the BAR immediately and
+     * add a subregion when we have the memory.
+     */
+    MemoryRegion bar;
+    MemoryRegion ivshmem;
     uint64_t ivshmem_size; /* size of shared memory region */
     int shm_fd; /* shared memory file descriptor */
 
@@ -96,23 +100,6 @@ static inline bool is_power_of_two(uint64_t x) {
     return (x & (x - 1)) == 0;
 }
 
-static void ivshmem_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    IVShmemState *s = DO_UPCAST(IVShmemState, dev, pci_dev);
-
-    s->shm_pci_addr = addr;
-
-    if (s->ivshmem_offset > 0) {
-        cpu_register_physical_memory(s->shm_pci_addr, s->ivshmem_size,
-                                                            s->ivshmem_offset);
-    }
-
-    IVSHMEM_DPRINTF("guest pci addr = %" FMT_PCIBUS ", guest h/w addr = %"
-        PRIu64 ", size = %" FMT_PCIBUS "\n", addr, s->ivshmem_offset, size);
-
-}
-
 /* accessing registers - based on rtl8139 */
 static void ivshmem_update_irq(IVShmemState *s, int val)
 {
@@ -168,15 +155,8 @@ static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
     return ret;
 }
 
-static void ivshmem_io_writew(void *opaque, target_phys_addr_t addr,
-                                                            uint32_t val)
-{
-
-    IVSHMEM_DPRINTF("We shouldn't be writing words\n");
-}
-
-static void ivshmem_io_writel(void *opaque, target_phys_addr_t addr,
-                                                            uint32_t val)
+static void ivshmem_io_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t val, unsigned size)
 {
     IVShmemState *s = opaque;
 
@@ -219,20 +199,8 @@ static void ivshmem_io_writel(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static void ivshmem_io_writeb(void *opaque, target_phys_addr_t addr,
-                                                                uint32_t val)
-{
-    IVSHMEM_DPRINTF("We shouldn't be writing bytes\n");
-}
-
-static uint32_t ivshmem_io_readw(void *opaque, target_phys_addr_t addr)
-{
-
-    IVSHMEM_DPRINTF("We shouldn't be reading words\n");
-    return 0;
-}
-
-static uint32_t ivshmem_io_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t ivshmem_io_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
 
     IVShmemState *s = opaque;
@@ -265,23 +233,14 @@ static uint32_t ivshmem_io_readl(void *opaque, target_phys_addr_t addr)
     return ret;
 }
 
-static uint32_t ivshmem_io_readb(void *opaque, target_phys_addr_t addr)
-{
-    IVSHMEM_DPRINTF("We shouldn't be reading bytes\n");
-
-    return 0;
-}
-
-static CPUReadMemoryFunc * const ivshmem_mmio_read[3] = {
-    ivshmem_io_readb,
-    ivshmem_io_readw,
-    ivshmem_io_readl,
-};
-
-static CPUWriteMemoryFunc * const ivshmem_mmio_write[3] = {
-    ivshmem_io_writeb,
-    ivshmem_io_writew,
-    ivshmem_io_writel,
+static const MemoryRegionOps ivshmem_mmio_ops = {
+    .read = ivshmem_io_read,
+    .write = ivshmem_io_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
 static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
@@ -371,12 +330,12 @@ static void create_shared_memory_BAR(IVShmemState *s, int fd) {
 
     ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
 
-    s->ivshmem_offset = qemu_ram_alloc_from_ptr(&s->dev.qdev, "ivshmem.bar2",
-                                                        s->ivshmem_size, ptr);
+    memory_region_init_ram_ptr(&s->ivshmem, &s->dev.qdev, "ivshmem.bar2",
+                               s->ivshmem_size, ptr);
+    memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
 
     /* region for shared memory */
-    pci_register_bar(&s->dev, 2, s->ivshmem_size,
-                                PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map);
+    pci_register_bar_region(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
 }
 
 static void close_guest_eventfds(IVShmemState *s, int posn)
@@ -401,8 +360,12 @@ static void setup_ioeventfds(IVShmemState *s) {
 
     for (i = 0; i <= s->max_peer; i++) {
         for (j = 0; j < s->peers[i].nb_eventfds; j++) {
-            kvm_set_ioeventfd_mmio_long(s->peers[i].eventfds[j],
-                    s->mmio_addr + DOORBELL, (i << 16) | j, 1);
+            memory_region_add_eventfd(&s->ivshmem_mmio,
+                                      DOORBELL,
+                                      4,
+                                      true,
+                                      (i << 16) | j,
+                                      s->peers[i].eventfds[j]);
         }
     }
 }
@@ -483,18 +446,13 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
         /* mmap the region and map into the BAR2 */
         map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
                                                             incoming_fd, 0);
-        s->ivshmem_offset = qemu_ram_alloc_from_ptr(&s->dev.qdev,
-                                    "ivshmem.bar2", s->ivshmem_size, map_ptr);
+        memory_region_init_ram_ptr(&s->ivshmem, &s->dev.qdev,
+                                   "ivshmem.bar2", s->ivshmem_size, map_ptr);
 
-        IVSHMEM_DPRINTF("guest pci addr = %" FMT_PCIBUS ", guest h/w addr = %"
-                         PRIu64 ", size = %" PRIu64 "\n", s->shm_pci_addr,
+        IVSHMEM_DPRINTF("guest h/w addr = %" PRIu64 ", size = %" PRIu64 "\n",
                          s->ivshmem_offset, s->ivshmem_size);
 
-        if (s->shm_pci_addr > 0) {
-            /* map memory into BAR2 */
-            cpu_register_physical_memory(s->shm_pci_addr, s->ivshmem_size,
-                                                            s->ivshmem_offset);
-        }
+        memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
 
         /* only store the fd if it is successfully mapped */
         s->shm_fd = incoming_fd;
@@ -549,20 +507,6 @@ static void ivshmem_reset(DeviceState *d)
     return;
 }
 
-static void ivshmem_mmio_map(PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
-{
-    IVShmemState *s = DO_UPCAST(IVShmemState, dev, pci_dev);
-
-    s->mmio_addr = addr;
-    cpu_register_physical_memory(addr + 0, IVSHMEM_REG_BAR_SIZE,
-                                                s->ivshmem_mmio_io_addr);
-
-    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
-        setup_ioeventfds(s);
-    }
-}
-
 static uint64_t ivshmem_get_size(IVShmemState * s) {
 
     uint64_t value;
@@ -710,15 +654,20 @@ static int pci_ivshmem_init(PCIDevice *dev)
 
     pci_config_set_interrupt_pin(pci_conf, 1);
 
-    s->shm_pci_addr = 0;
-    s->ivshmem_offset = 0;
     s->shm_fd = 0;
 
-    s->ivshmem_mmio_io_addr = cpu_register_io_memory(ivshmem_mmio_read,
-                                    ivshmem_mmio_write, s, DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->ivshmem_mmio, &ivshmem_mmio_ops, s,
+                          "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
+
+    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+        setup_ioeventfds(s);
+    }
+
     /* region for registers*/
-    pci_register_bar(&s->dev, 0, IVSHMEM_REG_BAR_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_mmio_map);
+    pci_register_bar_region(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                            &s->ivshmem_mmio);
+
+    memory_region_init(&s->bar, "ivshmem-bar2-container", s->ivshmem_size);
 
     if ((s->server_chr != NULL) &&
                         (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
@@ -744,8 +693,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
         /* allocate/initialize space for interrupt handling */
         s->peers = qemu_mallocz(s->nb_peers * sizeof(Peer));
 
-        pci_register_bar(&s->dev, 2, s->ivshmem_size,
-                                PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map);
+        pci_register_bar_region(&s->dev, 2,
+                                PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ivshmem);
 
         s->eventfd_chr = qemu_mallocz(s->vectors * sizeof(CharDriverState *));
 
@@ -792,7 +741,10 @@ static int pci_ivshmem_uninit(PCIDevice *dev)
 {
     IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
 
-    cpu_unregister_io_memory(s->ivshmem_mmio_io_addr);
+    memory_region_destroy(&s->ivshmem_mmio);
+    memory_region_del_subregion(&s->bar, &s->ivshmem);
+    memory_region_destroy(&s->ivshmem);
+    memory_region_destroy(&s->bar);
     unregister_savevm(&dev->qdev, "ivshmem", s);
 
     return 0;
