diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 347718f..c371588 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -24,6 +24,7 @@
 #include "exec/address-spaces.h"
 #include "intel_iommu_internal.h"
 #include "hw/pci/pci.h"
+#include "hw/i386/pc.h"
 
 /*#define DEBUG_INTEL_IOMMU*/
 #ifdef DEBUG_INTEL_IOMMU
@@ -266,6 +267,11 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
     g_hash_table_replace(s->iotlb, key, entry);
 }
 
+static AddressSpace *get_dma_address_space(void)
+{
+    return &PC_MACHINE(qdev_get_machine())->dma_address_space;
+}
+
 /* Given the reg addr of both the message data and address, generate an
  * interrupt via MSI.
  */
@@ -282,7 +288,7 @@ static void vtd_generate_interrupt(IntelIOMMUState *s, hwaddr mesg_addr_reg,
     data = vtd_get_long_raw(s, mesg_data_reg);
 
     VTD_DPRINTF(FLOG, "msi: addr 0x%"PRIx64 " data 0x%"PRIx32, addr, data);
-    address_space_stl_le(&address_space_memory, addr, data,
+    address_space_stl_le(get_dma_address_space(), addr, data,
                          MEMTXATTRS_UNSPECIFIED, NULL);
 }
 
@@ -496,7 +502,7 @@ static int vtd_get_root_entry(IntelIOMMUState *s, uint8_t index,
     dma_addr_t addr;
 
     addr = s->root + index * sizeof(*re);
-    if (dma_memory_read(&address_space_memory, addr, re, sizeof(*re))) {
+    if (dma_memory_read(get_dma_address_space(), addr, re, sizeof(*re))) {
         VTD_DPRINTF(GENERAL, "error: fail to access root-entry at 0x%"PRIx64
                     " + %"PRIu8, s->root, index);
         re->val = 0;
@@ -521,7 +527,7 @@ static int vtd_get_context_entry_from_root(VTDRootEntry *root, uint8_t index,
         return -VTD_FR_ROOT_ENTRY_P;
     }
     addr = (root->val & VTD_ROOT_ENTRY_CTP) + index * sizeof(*ce);
-    if (dma_memory_read(&address_space_memory, addr, ce, sizeof(*ce))) {
+    if (dma_memory_read(get_dma_address_space(), addr, ce, sizeof(*ce))) {
         VTD_DPRINTF(GENERAL, "error: fail to access context-entry at 0x%"PRIx64
                     " + %"PRIu8,
                     (uint64_t)(root->val & VTD_ROOT_ENTRY_CTP), index);
@@ -555,7 +561,7 @@ static uint64_t vtd_get_slpte(dma_addr_t base_addr, uint32_t index)
 
     assert(index < VTD_SL_PT_ENTRY_NR);
 
-    if (dma_memory_read(&address_space_memory,
+    if (dma_memory_read(get_dma_address_space(),
                         base_addr + index * sizeof(slpte), &slpte,
                         sizeof(slpte))) {
         slpte = (uint64_t)-1;
@@ -1227,7 +1233,7 @@ static bool vtd_get_inv_desc(dma_addr_t base_addr, uint32_t offset,
                              VTDInvDesc *inv_desc)
 {
     dma_addr_t addr = base_addr + offset * sizeof(*inv_desc);
-    if (dma_memory_read(&address_space_memory, addr, inv_desc,
+    if (dma_memory_read(get_dma_address_space(), addr, inv_desc,
         sizeof(*inv_desc))) {
         VTD_DPRINTF(GENERAL, "error: fail to fetch Invalidation Descriptor "
                     "base_addr 0x%"PRIx64 " offset %"PRIu32, base_addr, offset);
@@ -1262,8 +1268,8 @@ static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
         VTD_DPRINTF(INV, "status data 0x%x, status addr 0x%"PRIx64,
                     status_data, status_addr);
         status_data = cpu_to_le32(status_data);
-        if (dma_memory_write(&address_space_memory, status_addr, &status_data,
-                             sizeof(status_data))) {
+        if (dma_memory_write(get_dma_address_space(), status_addr,
+                             &status_data, sizeof(status_data))) {
             VTD_DPRINTF(GENERAL, "error: fail to perform a coherent write");
             return false;
         }
@@ -1845,7 +1851,7 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr,
     VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
     IntelIOMMUState *s = vtd_as->iommu_state;
     IOMMUTLBEntry ret = {
-        .target_as = &address_space_memory,
+        .target_as = get_dma_address_space(),
         .iova = addr,
         .translated_addr = 0,
         .addr_mask = ~(hwaddr)0,
diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c
index 694d398..5f55cf1 100644
--- a/hw/i386/kvm/apic.c
+++ b/hw/i386/kvm/apic.c
@@ -10,6 +10,7 @@
  * See the COPYING file in the top-level directory.
  */
 #include "qemu/osdep.h"
+#include "hw/i386/apic-msidef.h"
 #include "hw/i386/apic_internal.h"
 #include "hw/pci/msi.h"
 #include "sysemu/kvm.h"
@@ -147,14 +148,13 @@ static void kvm_apic_external_nmi(APICCommonState *s)
     run_on_cpu(CPU(s->cpu), do_inject_external_nmi, s);
 }
 
-static uint64_t kvm_apic_mem_read(void *opaque, hwaddr addr,
-                                  unsigned size)
+static uint64_t kvm_msi_region_read(void *opaque, hwaddr addr, unsigned size)
 {
     return ~(uint64_t)0;
 }
 
-static void kvm_apic_mem_write(void *opaque, hwaddr addr,
-                               uint64_t data, unsigned size)
+static void kvm_msi_region_write(void *opaque, hwaddr addr, uint64_t data,
+                                 unsigned size)
 {
     MSIMessage msg = { .address = addr, .data = data };
     int ret;
@@ -166,10 +166,14 @@ static void kvm_apic_mem_write(void *opaque, hwaddr addr,
     }
 }
 
-static const MemoryRegionOps kvm_apic_io_ops = {
-    .read = kvm_apic_mem_read,
-    .write = kvm_apic_mem_write,
+static const MemoryRegionOps kvm_msi_region_ops = {
+    .read = kvm_msi_region_read,
+    .write = kvm_msi_region_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
 static void kvm_apic_reset(APICCommonState *s)
@@ -182,8 +186,10 @@ static void kvm_apic_realize(DeviceState *dev, Error **errp)
 {
     APICCommonState *s = APIC_COMMON(dev);
 
-    memory_region_init_io(&s->io_memory, NULL, &kvm_apic_io_ops, s, "kvm-apic-msi",
-                          APIC_SPACE_SIZE);
+    memory_region_init(&s->io_memory, NULL, "kvm-apic", APIC_SPACE_SIZE);
+
+    memory_region_init_io(&s->msi_region, NULL, &kvm_msi_region_ops, NULL,
+                          "kvm-msi", MSI_REGION_SIZE);
 
     if (kvm_has_gsi_routing()) {
         msi_supported = true;
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 0aeefd2..608d903 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -26,6 +26,7 @@
 #include "hw/i386/pc.h"
 #include "hw/char/serial.h"
 #include "hw/i386/apic.h"
+#include "hw/i386/apic-msidef.h"
 #include "hw/i386/topology.h"
 #include "sysemu/cpus.h"
 #include "hw/block/fdc.h"
@@ -1281,6 +1282,7 @@ void pc_memory_init(PCMachineState *pcms,
     FWCfgState *fw_cfg;
     MachineState *machine = MACHINE(pcms);
     PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
+    MemoryRegion *dma, *mem_alias;
 
     assert(machine->ram_size == pcms->below_4g_mem_size +
                                 pcms->above_4g_mem_size);
@@ -1360,6 +1362,21 @@ void pc_memory_init(PCMachineState *pcms,
                                     &pcms->hotplug_memory.mr);
     }
 
+    /* Initialized DMA address space */
+    dma = g_malloc(sizeof(*dma));
+    memory_region_init(dma, NULL, "dma-container",
+                       memory_region_size(system_memory));
+    address_space_init(&pcms->dma_address_space, dma, "pc-dma");
+
+    mem_alias = g_malloc(sizeof(*mem_alias));
+    memory_region_init_alias(mem_alias, NULL, "system-memory", system_memory,
+                             0, memory_region_size(system_memory));
+    memory_region_add_subregion_overlap(dma, 0, mem_alias, 0);
+
+    pci_set_dma_address_space(&pcms->dma_address_space);
+    pcms->ioapic_msi_target = &pcms->dma_address_space;
+    pcms->hpet_msi_target = &pcms->dma_address_space;
+
     /* Initialize PC system firmware */
     pc_system_firmware_init(rom_memory, !pcmc->pci_enabled);
 
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 6f8c2cd..21ac546 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -126,7 +126,6 @@ static void pc_init1(MachineState *machine,
     }
 
     pc_cpus_init(pcms);
-
     if (kvm_enabled() && pcmc->kvmclock_enabled) {
         kvmclock_create();
     }
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 46522c9..13fc647 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -113,10 +113,6 @@ static void pc_q35_init(MachineState *machine)
         xen_hvm_init(pcms, &ram_memory);
     }
 
-    pc_cpus_init(pcms);
-
-    kvmclock_create();
-
     /* pci enabled */
     if (pcmc->pci_enabled) {
         pci_memory = g_new(MemoryRegion, 1);
@@ -143,6 +139,13 @@ static void pc_q35_init(MachineState *machine)
                        rom_memory, &ram_memory);
     }
 
+    pc_cpus_init(pcms);
+    if (!pcmc->has_acpi_build) {
+        /* only machine types 1.7 & older need this */
+        pc_acpi_init("q35-acpi-dsdt.aml");
+    }
+
+    kvmclock_create();
     /* irq lines */
     gsi_state = g_malloc0(sizeof(*gsi_state));
     if (kvm_irqchip_in_kernel()) {
diff --git a/hw/i386/xen/xen_apic.c b/hw/i386/xen/xen_apic.c
index 2b8d709..71d52f4 100644
--- a/hw/i386/xen/xen_apic.c
+++ b/hw/i386/xen/xen_apic.c
@@ -10,18 +10,18 @@
  * later. See the COPYING file in the top-level directory.
  */
 #include "qemu/osdep.h"
+#include "hw/i386/apic-msidef.h"
 #include "hw/i386/apic_internal.h"
 #include "hw/pci/msi.h"
 #include "hw/xen/xen.h"
 
-static uint64_t xen_apic_mem_read(void *opaque, hwaddr addr,
-                                  unsigned size)
+static uint64_t xen_msi_region_read(void *opaque, hwaddr addr, unsigned size)
 {
     return ~(uint64_t)0;
 }
 
-static void xen_apic_mem_write(void *opaque, hwaddr addr,
-                               uint64_t data, unsigned size)
+static void xen_msi_region_write(void *opaque, hwaddr addr, uint64_t data,
+                                 unsigned size)
 {
     if (size != sizeof(uint32_t)) {
         fprintf(stderr, "Xen: APIC write data size = %d, invalid\n", size);
@@ -31,10 +31,14 @@ static void xen_apic_mem_write(void *opaque, hwaddr addr,
     xen_hvm_inject_msi(addr, data);
 }
 
-static const MemoryRegionOps xen_apic_io_ops = {
-    .read = xen_apic_mem_read,
-    .write = xen_apic_mem_write,
+static const MemoryRegionOps xen_msi_region_ops = {
+    .read = xen_msi_region_read,
+    .write = xen_msi_region_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
 static void xen_apic_realize(DeviceState *dev, Error **errp)
@@ -42,8 +46,10 @@ static void xen_apic_realize(DeviceState *dev, Error **errp)
     APICCommonState *s = APIC_COMMON(dev);
 
     s->vapic_control = 0;
-    memory_region_init_io(&s->io_memory, OBJECT(s), &xen_apic_io_ops, s,
-                          "xen-apic-msi", APIC_SPACE_SIZE);
+    memory_region_init(&s->io_memory, NULL, "xen-apic", APIC_SPACE_SIZE);
+
+    memory_region_init_io(&s->msi_region, NULL, &xen_msi_region_ops, NULL,
+                          "xen-msi", MSI_REGION_SIZE);
     msi_supported = true;
 }
 
diff --git a/hw/intc/apic.c b/hw/intc/apic.c
index a299462..2e99f75 100644
--- a/hw/intc/apic.c
+++ b/hw/intc/apic.c
@@ -732,31 +732,11 @@ static uint32_t apic_mem_readl(void *opaque, hwaddr addr)
     return val;
 }
 
-static void apic_send_msi(hwaddr addr, uint32_t data)
-{
-    uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
-    uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
-    uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
-    uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
-    uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
-    /* XXX: Ignore redirection hint. */
-    apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
-}
-
 static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val)
 {
     DeviceState *dev;
     APICCommonState *s;
     int index = (addr >> 4) & 0xff;
-    if (addr > 0xfff || !index) {
-        /* MSI and MMIO APIC are at the same memory location,
-         * but actually not on the global bus: MSI is on PCI bus
-         * APIC is connected directly to the CPU.
-         * Mapping them on the global bus happens to work because
-         * MSI registers are reserved in APIC MMIO and vice versa. */
-        apic_send_msi(addr, val);
-        return;
-    }
 
     dev = cpu_get_current_apic();
     if (!dev) {
@@ -856,6 +836,34 @@ static void apic_post_load(APICCommonState *s)
     }
 }
 
+static void msi_region_write(void *opaque, hwaddr addr, uint64_t data,
+                             unsigned size)
+{
+    uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
+    uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
+    uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
+    uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
+    uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
+    /* FIXME: Ignoring redirection hint. */
+
+    apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
+}
+
+static uint64_t msi_region_read(void *opaque, hwaddr addr, unsigned size)
+{
+    return ~(uint64_t)0;
+}
+
+static const MemoryRegionOps msi_region_ops = {
+    .write = msi_region_write,
+    .read = msi_region_read,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
 static const MemoryRegionOps apic_io_ops = {
     .old_mmio = {
         .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, },
@@ -868,9 +876,12 @@ static void apic_realize(DeviceState *dev, Error **errp)
 {
     APICCommonState *s = APIC_COMMON(dev);
 
-    memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi",
+    memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic",
                           APIC_SPACE_SIZE);
 
+    memory_region_init_io(&s->msi_region, NULL, &msi_region_ops, NULL, "msi",
+                          MSI_REGION_SIZE);
+
     s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s);
     local_apics[s->idx] = s;
 
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
index 659f377..b54eb7c 100644
--- a/hw/intc/apic_common.c
+++ b/hw/intc/apic_common.c
@@ -19,7 +19,9 @@
  */
 #include "qemu/osdep.h"
 #include "hw/i386/apic.h"
+#include "hw/i386/apic-msidef.h"
 #include "hw/i386/apic_internal.h"
+#include "hw/i386/pc.h"
 #include "trace.h"
 #include "sysemu/kvm.h"
 #include "hw/qdev.h"
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 378e663..7bc7ee4 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -23,6 +23,7 @@
 #include "qemu/osdep.h"
 #include "monitor/monitor.h"
 #include "hw/hw.h"
+#include "hw/i386/apic-msidef.h"
 #include "hw/i386/pc.h"
 #include "hw/i386/ioapic.h"
 #include "hw/i386/ioapic_internal.h"
@@ -49,31 +50,31 @@ extern int ioapic_no;
 
 static void ioapic_service(IOAPICCommonState *s)
 {
+    AddressSpace *msi_as = PC_MACHINE(qdev_get_machine())->ioapic_msi_target;
+    uint32_t addr, data;
     uint8_t i;
     uint8_t trig_mode;
     uint8_t vector;
     uint8_t delivery_mode;
     uint32_t mask;
     uint64_t entry;
-    uint8_t dest;
+    uint16_t dest_idx;
     uint8_t dest_mode;
 
     for (i = 0; i < IOAPIC_NUM_PINS; i++) {
         mask = 1 << i;
         if (s->irr & mask) {
-            int coalesce = 0;
 
             entry = s->ioredtbl[i];
             if (!(entry & IOAPIC_LVT_MASKED)) {
                 trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1);
-                dest = entry >> IOAPIC_LVT_DEST_SHIFT;
+                dest_idx = entry >> IOAPIC_LVT_DEST_IDX_SHIFT;
                 dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
                 delivery_mode =
                     (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK;
                 if (trig_mode == IOAPIC_TRIGGER_EDGE) {
                     s->irr &= ~mask;
                 } else {
-                    coalesce = s->ioredtbl[i] & IOAPIC_LVT_REMOTE_IRR;
                     s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
                 }
                 if (delivery_mode == IOAPIC_DM_EXTINT) {
@@ -81,23 +82,12 @@ static void ioapic_service(IOAPICCommonState *s)
                 } else {
                     vector = entry & IOAPIC_VECTOR_MASK;
                 }
-#ifdef CONFIG_KVM
-                if (kvm_irqchip_is_split()) {
-                    if (trig_mode == IOAPIC_TRIGGER_EDGE) {
-                        kvm_set_irq(kvm_state, i, 1);
-                        kvm_set_irq(kvm_state, i, 0);
-                    } else {
-                        if (!coalesce) {
-                            kvm_set_irq(kvm_state, i, 1);
-                        }
-                    }
-                    continue;
-                }
-#else
-                (void)coalesce;
-#endif
-                apic_deliver_irq(dest, dest_mode, delivery_mode, vector,
-                                 trig_mode);
+                addr = MSI_ADDR_BASE | (dest_idx << MSI_ADDR_DEST_IDX_SHIFT) |
+                    (dest_mode << MSI_ADDR_DEST_MODE_SHIFT);
+                data = (vector << MSI_DATA_VECTOR_SHIFT) |
+                    (trig_mode << MSI_DATA_TRIGGER_SHIFT) |
+                    (delivery_mode << MSI_DATA_DELIVERY_MODE_SHIFT);
+                stl_le_phys(msi_as, addr, data);
             }
         }
     }
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 115fb8c..566e3d8 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -436,6 +436,7 @@ static AddressSpace *q35_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
 
 static void mch_init_dmar(MCHPCIState *mch)
 {
+    PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
     PCIBus *pci_bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch)));
 
     mch->iommu = INTEL_IOMMU_DEVICE(qdev_create(NULL, TYPE_INTEL_IOMMU_DEVICE));
@@ -445,6 +446,12 @@ static void mch_init_dmar(MCHPCIState *mch)
     sysbus_mmio_map(SYS_BUS_DEVICE(mch->iommu), 0, Q35_HOST_BRIDGE_IOMMU_ADDR);
 
     pci_setup_iommu(pci_bus, q35_host_dma_iommu, mch->iommu);
+
+    pcms->ioapic_msi_target = q35_host_dma_iommu(pci_bus, mch->iommu,
+                              Q35_PSEUDO_DEVFN_IOAPIC);
+
+    pcms->hpet_msi_target = q35_host_dma_iommu(pci_bus, mch->iommu,
+                              Q35_PSEUDO_DEVFN_HPET);
 }
 
 static void mch_realize(PCIDevice *d, Error **errp)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index e67664d..bad2055 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -52,6 +52,7 @@ static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent);
 static char *pcibus_get_dev_path(DeviceState *dev);
 static char *pcibus_get_fw_dev_path(DeviceState *dev);
 static void pcibus_reset(BusState *qbus);
+static AddressSpace *pci_dma_address_space = &address_space_memory;
 
 static Property pci_props[] = {
     DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
@@ -2396,6 +2397,11 @@ static void pci_device_class_init(ObjectClass *klass, void *data)
     pc->realize = pci_default_realize;
 }
 
+void pci_set_dma_address_space(AddressSpace *dma_address_space)
+{
+    pci_dma_address_space = dma_address_space;
+}
+
 AddressSpace *pci_device_iommu_address_space(PCIDevice *dev)
 {
     PCIBus *bus = PCI_BUS(dev->bus);
@@ -2407,7 +2413,7 @@ AddressSpace *pci_device_iommu_address_space(PCIDevice *dev)
     if (iommu_bus && iommu_bus->iommu_fn) {
         return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, dev->devfn);
     }
-    return &address_space_memory;
+    return pci_dma_address_space;
 }
 
 void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque)
diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
index 0ad5420..f36ae68 100644
--- a/hw/timer/hpet.c
+++ b/hw/timer/hpet.c
@@ -208,9 +208,9 @@ static void update_irq(struct HPETTimer *timer, int set)
             }
         }
     } else if (timer_fsb_route(timer)) {
-        address_space_stl_le(&address_space_memory, timer->fsb >> 32,
-                             timer->fsb & 0xffffffff, MEMTXATTRS_UNSPECIFIED,
-                             NULL);
+        address_space_stl_le(PC_MACHINE(qdev_get_machine())->hpet_msi_target,
+                             timer->fsb >> 32, timer->fsb & 0xffffffff,
+                             MEMTXATTRS_UNSPECIFIED, NULL);
     } else if (timer->config & HPET_TN_TYPE_LEVEL) {
         s->isr |= mask;
         /* fold the ICH PIRQ# pin's internal inversion logic into hpet */
diff --git a/include/hw/i386/apic-msidef.h b/include/hw/i386/apic-msidef.h
index 6e2eb71..5052f23 100644
--- a/include/hw/i386/apic-msidef.h
+++ b/include/hw/i386/apic-msidef.h
@@ -5,6 +5,9 @@
  * Intel APIC constants: from include/asm/msidef.h
  */
 
+#define MSI_ADDR_BASE                   0xfee00000
+#define MSI_REGION_SIZE                 0x00100000
+
 /*
  * Shifts for MSI data
  */
@@ -25,6 +28,7 @@
 #define MSI_ADDR_REDIRECTION_SHIFT      3
 
 #define MSI_ADDR_DEST_ID_SHIFT          12
+#define MSI_ADDR_DEST_IDX_SHIFT         4
 #define  MSI_ADDR_DEST_ID_MASK          0x00ffff0
 
 #endif /* HW_APIC_MSIDEF_H */
diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h
index 74fe935..ad5ffe5 100644
--- a/include/hw/i386/apic_internal.h
+++ b/include/hw/i386/apic_internal.h
@@ -154,6 +154,7 @@ struct APICCommonState {
     /*< public >*/
 
     MemoryRegion io_memory;
+    MemoryRegion msi_region;
     X86CPU *cpu;
     uint32_t apicbase;
     uint8_t id;
diff --git a/include/hw/i386/ioapic_internal.h b/include/hw/i386/ioapic_internal.h
index 797ed47..d279f2d 100644
--- a/include/hw/i386/ioapic_internal.h
+++ b/include/hw/i386/ioapic_internal.h
@@ -31,6 +31,7 @@
 #define IOAPIC_VERSION                  0x11
 
 #define IOAPIC_LVT_DEST_SHIFT           56
+#define IOAPIC_LVT_DEST_IDX_SHIFT       48
 #define IOAPIC_LVT_MASKED_SHIFT         16
 #define IOAPIC_LVT_TRIGGER_MODE_SHIFT   15
 #define IOAPIC_LVT_REMOTE_IRR_SHIFT     14
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 8b3546e..1bdabf6 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -36,6 +36,9 @@
 /**
  * PCMachineState:
  * @acpi_dev: link to ACPI PM device that performs ACPI hotplug handling
+ * @dma_address_space: target address space for DMA from I/O devices
+ * @ioapic_msi_target: target address space for IOAPIC interrupt messages
+ * @hpet_msi_target: target address space for HPET interrupt messages
  */
 struct PCMachineState {
     /*< private >*/
@@ -65,6 +68,9 @@ struct PCMachineState {
     /* CPU and apic information: */
     bool apic_xrupt_override;
     unsigned apic_id_limit;
+    AddressSpace dma_address_space;
+    AddressSpace *ioapic_msi_target;
+    AddressSpace *hpet_msi_target;
 
     /* NUMA information: */
     uint64_t numa_nodes;
diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
index c5c073d..fc87013 100644
--- a/include/hw/pci-host/q35.h
+++ b/include/hw/pci-host/q35.h
@@ -74,6 +74,10 @@ typedef struct Q35PCIHost {
 #define Q35_MASK(bit, ms_bit, ls_bit) \
 ((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1)))
 
+#define Q35_PSEUDO_BUS_PLATFORM         0xff
+#define Q35_PSEUDO_DEVFN_IOAPIC         0x01
+#define Q35_PSEUDO_DEVFN_HPET           0x02
+
 /*
  * gmch part
  */
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 0be07c8..d37b546 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -417,6 +417,8 @@ void pci_bus_get_w64_range(PCIBus *bus, Range *range);
 
 void pci_device_deassert_intx(PCIDevice *dev);
 
+void pci_set_dma_address_space(AddressSpace *dma_address_space);
+
 typedef AddressSpace *(*PCIIOMMUFunc)(PCIBus *, void *, int);
 
 AddressSpace *pci_device_iommu_address_space(PCIDevice *dev);
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 0f38d1e..6ac1382 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -23,6 +23,8 @@
 #include "sysemu/cpus.h"
 #include "kvm_i386.h"
 
+#include "hw/i386/pc.h"
+#include "hw/i386/apic-msidef.h"
 #include "qemu/error-report.h"
 #include "qemu/option.h"
 #include "qemu/config-file.h"
@@ -2821,6 +2823,7 @@ static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
 {
     APICCommonState *apic;
     static bool apic_mmio_map_once;
+    AddressSpace *dma_as;
 
     if (cpu->apic_state == NULL) {
         return;
@@ -2836,6 +2839,10 @@ static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
                                             MSR_IA32_APICBASE_BASE,
                                             &apic->io_memory,
                                             0x1000);
+
+        dma_as = &PC_MACHINE(qdev_get_machine())->dma_address_space;
+        memory_region_add_subregion_overlap(dma_as->root, MSI_ADDR_BASE,
+                                            &apic->msi_region, 1);
         apic_mmio_map_once = true;
      }
 }
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 5148c82..fddca76 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -1376,7 +1376,7 @@ const char *get_register_name_32(unsigned int reg);
 void enable_compat_apic_id_mode(void);
 
 #define APIC_DEFAULT_ADDRESS 0xfee00000
-#define APIC_SPACE_SIZE      0x100000
+#define APIC_SPACE_SIZE      0x1000
 
 void x86_cpu_dump_local_apic_state(CPUState *cs, FILE *f,
                                    fprintf_function cpu_fprintf, int flags);
