diff --git a/hw/arm/xen_arm.c b/hw/arm/xen_arm.c
index b9c3ae14b6..dc6d3a1d82 100644
--- a/hw/arm/xen_arm.c
+++ b/hw/arm/xen_arm.c
@@ -34,6 +34,7 @@
 #include "hw/xen/xen-hvm-common.h"
 #include "sysemu/tpm.h"
 #include "hw/xen/arch_hvm.h"
+#include "hw/pci-host/gpex.h"
 
 #define TYPE_XEN_ARM  MACHINE_TYPE_NAME("xenpvh")
 OBJECT_DECLARE_SIMPLE_TYPE(XenArmState, XEN_ARM)
@@ -57,6 +58,10 @@ struct XenArmState {
 
     struct {
         uint64_t tpm_base_addr;
+        MemMapEntry pcie_mmio;
+        MemMapEntry pcie_ecam;
+        MemMapEntry pcie_mmio_high;
+        int         pcie_irq_base;
     } cfg;
 };
 
@@ -73,6 +78,15 @@ static MemoryRegion ram_lo, ram_hi;
 #define NR_VIRTIO_MMIO_DEVICES   \
    (GUEST_VIRTIO_MMIO_SPI_LAST - GUEST_VIRTIO_MMIO_SPI_FIRST)
 
+#define XEN_ARM_PCIE_ECAM_BASE          "pcie-ecam-base"
+#define XEN_ARM_PCIE_ECAM_SIZE          "pcie-ecam-size"
+#define XEN_ARM_PCIE_MEM_BASE           "pcie-mem-base"
+#define XEN_ARM_PCIE_MEM_SIZE           "pcie-mem-size"
+#define XEN_ARM_PCIE_PREFETCH_BASE      "pcie-prefetch-mem-base"
+#define XEN_ARM_PCIE_PREFETCH_SIZE      "pcie-prefetch-mem-size"
+#define XEN_ARM_PCIE_IRQ_BASE           "pcie-irq-base"
+
+/* TODO It should be xendevicemodel_set_pci_intx_level() for PCI interrupts. */
 static void xen_set_irq(void *opaque, int irq, int level)
 {
     if (xendevicemodel_set_irq_level(xen_dmod, xen_domid, irq, level)) {
@@ -129,6 +143,89 @@ static void xen_init_ram(MachineState *machine)
     }
 }
 
+static bool xen_validate_pcie_config(XenArmState *xam)
+{
+    if (xam->cfg.pcie_ecam.base == 0 &&
+        xam->cfg.pcie_ecam.size == 0 &&
+        xam->cfg.pcie_mmio.base == 0 &&
+        xam->cfg.pcie_mmio.size == 0 &&
+        xam->cfg.pcie_mmio_high.base == 0 &&
+        xam->cfg.pcie_mmio_high.size == 0 &&
+        xam->cfg.pcie_irq_base == 0) {
+
+        /* It's okay, user just don't want PCIe brige */
+
+        return false;
+    }
+
+    if (xam->cfg.pcie_ecam.base == 0 ||
+        xam->cfg.pcie_ecam.size == 0 ||
+        xam->cfg.pcie_mmio.base == 0 ||
+        xam->cfg.pcie_mmio.size == 0 ||
+        xam->cfg.pcie_mmio_high.base == 0 ||
+        xam->cfg.pcie_mmio_high.size == 0 ||
+        xam->cfg.pcie_irq_base == 0) {
+
+        /* User provided some PCIe options, but not all of them */
+
+        error_printf("Incomplete PCIe bridge configuration\n");
+
+        exit(1);
+    }
+
+    return true;
+}
+
+static void xen_create_pcie(XenArmState *xam)
+{
+    MemoryRegion *mmio_alias, *mmio_alias_high, *mmio_reg;
+    MemoryRegion *ecam_alias, *ecam_reg;
+    DeviceState *dev;
+    int i;
+
+    dev = qdev_new(TYPE_GPEX_HOST);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+    /* Map ECAM space */
+    ecam_alias = g_new0(MemoryRegion, 1);
+    ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+    memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
+                             ecam_reg, 0, xam->cfg.pcie_ecam.size);
+    memory_region_add_subregion(get_system_memory(), xam->cfg.pcie_ecam.base,
+                                ecam_alias);
+
+    /* Map the MMIO space */
+    mmio_alias = g_new0(MemoryRegion, 1);
+    mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+    memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
+                             mmio_reg,
+                             xam->cfg.pcie_mmio.base,
+                             xam->cfg.pcie_mmio.size);
+    memory_region_add_subregion(get_system_memory(), xam->cfg.pcie_mmio.base,
+                                mmio_alias);
+
+    /* Map the MMIO_HIGH space */
+    mmio_alias_high = g_new0(MemoryRegion, 1);
+    memory_region_init_alias(mmio_alias_high, OBJECT(dev), "pcie-mmio-high",
+                             mmio_reg,
+                             xam->cfg.pcie_mmio_high.base,
+                             xam->cfg.pcie_mmio_high.size);
+    memory_region_add_subregion(get_system_memory(),
+                                xam->cfg.pcie_mmio_high.base,
+                                mmio_alias_high);
+
+    /* Legacy PCI interrupts (#INTA - #INTD) */
+    for (i = 0; i < GPEX_NUM_IRQS; i++) {
+        qemu_irq irq = qemu_allocate_irq(xen_set_irq, NULL,
+                                         xam->cfg.pcie_irq_base + i);
+
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
+        gpex_set_irq_num(GPEX_HOST(dev), i, xam->cfg.pcie_irq_base + i);
+    }
+
+    DPRINTF("Created PCIe host bridge\n");
+}
+
 void arch_handle_ioreq(XenIOState *state, ioreq_t *req)
 {
     hw_error("Invalid ioreq type 0x%x\n", req->type);
@@ -189,6 +286,12 @@ static void xen_arm_init(MachineState *machine)
     xen_register_ioreq(xam->state, machine->smp.cpus, &xen_memory_listener);
 
     xen_create_virtio_mmio_devices(xam);
+    if (xen_validate_pcie_config(xam)) {
+        xen_create_pcie(xam);
+    } else {
+        DPRINTF("PCIe host bridge is not configured,"
+                " only virtio-mmio can be used\n");
+    }
 
 #ifdef CONFIG_TPM
     if (xam->cfg.tpm_base_addr) {
@@ -225,6 +328,90 @@ static void xen_arm_set_tpm_base_addr(Object *obj, Visitor *v,
 }
 #endif
 
+static void xen_arm_get_pcie_prop(Object *obj, Visitor *v,
+                                  const char *name, void *opaque,
+                                  Error **errp)
+{
+    XenArmState *xam = XEN_ARM(obj);
+    hwaddr *target;
+
+    if (!strcmp(name, XEN_ARM_PCIE_ECAM_BASE)) {
+        target = &xam->cfg.pcie_ecam.base;
+    } else if (!strcmp(name, XEN_ARM_PCIE_ECAM_SIZE)) {
+        target = &xam->cfg.pcie_ecam.size;
+    } else if (!strcmp(name, XEN_ARM_PCIE_MEM_BASE)) {
+        target = &xam->cfg.pcie_mmio.base;
+    } else if (!strcmp(name, XEN_ARM_PCIE_MEM_SIZE)) {
+        target = &xam->cfg.pcie_mmio.size;
+    } else if (!strcmp(name, XEN_ARM_PCIE_PREFETCH_BASE)) {
+        target = &xam->cfg.pcie_mmio_high.base;
+    } else if (!strcmp(name, XEN_ARM_PCIE_PREFETCH_SIZE)) {
+        target = &xam->cfg.pcie_mmio_high.size;
+    } else {
+        /* Unreachable */
+        assert(false);
+        return;
+    }
+
+    visit_type_uint64(v, name, target, errp);
+}
+
+static void xen_arm_set_pcie_prop(Object *obj, Visitor *v,
+                                  const char *name, void *opaque,
+                                  Error **errp)
+{
+    XenArmState *xam = XEN_ARM(obj);
+    uint64_t value;
+    hwaddr *target;
+
+    if (!strcmp(name, XEN_ARM_PCIE_ECAM_BASE)) {
+        target = &xam->cfg.pcie_ecam.base;
+    } else if (!strcmp(name, XEN_ARM_PCIE_ECAM_SIZE)) {
+        target = &xam->cfg.pcie_ecam.size;
+    } else if (!strcmp(name, XEN_ARM_PCIE_MEM_BASE)) {
+        target = &xam->cfg.pcie_mmio.base;
+    } else if (!strcmp(name, XEN_ARM_PCIE_MEM_SIZE)) {
+        target = &xam->cfg.pcie_mmio.size;
+    } else if (!strcmp(name, XEN_ARM_PCIE_PREFETCH_BASE)) {
+        target = &xam->cfg.pcie_mmio_high.base;
+    } else if (!strcmp(name, XEN_ARM_PCIE_PREFETCH_SIZE)) {
+        target = &xam->cfg.pcie_mmio_high.size;
+    } else {
+        /* Unreachable */
+        assert(false);
+        return;
+    }
+
+    if (!visit_type_uint64(v, name, &value, errp)) {
+        return;
+    }
+    *target = value;
+}
+
+static void xen_arm_get_pcie_irq_base(Object *obj, Visitor *v,
+                                      const char *name, void *opaque,
+                                      Error **errp)
+{
+    XenArmState *xam = XEN_ARM(obj);
+    int64_t value = xam->cfg.pcie_irq_base;
+
+    visit_type_int(v, name, &value, errp);
+}
+
+static void xen_arm_set_pcie_irq_base(Object *obj, Visitor *v,
+                                      const char *name, void *opaque,
+                                      Error **errp)
+{
+    XenArmState *xam = XEN_ARM(obj);
+    int64_t value;
+
+    if (!visit_type_int(v, name, &value, errp)) {
+        return;
+    }
+
+    xam->cfg.pcie_irq_base = value;
+}
+
 static void xen_arm_machine_class_init(ObjectClass *oc, void *data)
 {
 
@@ -246,6 +433,45 @@ static void xen_arm_machine_class_init(ObjectClass *oc, void *data)
 
     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
 #endif
+
+    object_class_property_add(oc, XEN_ARM_PCIE_ECAM_BASE, "uint64_t",
+                              xen_arm_get_pcie_prop,
+                              xen_arm_set_pcie_prop, NULL, NULL);
+    object_class_property_set_description(oc, XEN_ARM_PCIE_ECAM_BASE,
+        "Base address for ECAM range of virtual PCIe host bridge");
+    object_class_property_add(oc, XEN_ARM_PCIE_ECAM_SIZE, "uint64_t",
+                              xen_arm_get_pcie_prop,
+                              xen_arm_set_pcie_prop, NULL, NULL);
+    object_class_property_set_description(oc, XEN_ARM_PCIE_ECAM_SIZE,
+        "Size of ECAM range of virtual PCIe host bridge");
+
+    object_class_property_add(oc, XEN_ARM_PCIE_MEM_BASE, "uint64_t",
+                              xen_arm_get_pcie_prop,
+                              xen_arm_set_pcie_prop, NULL, NULL);
+    object_class_property_set_description(oc, XEN_ARM_PCIE_MEM_BASE,
+        "Base address for non-prefetchable memory of virtual PCIe host bridge");
+    object_class_property_add(oc, XEN_ARM_PCIE_MEM_SIZE, "uint64_t",
+                              xen_arm_get_pcie_prop,
+                              xen_arm_set_pcie_prop, NULL, NULL);
+    object_class_property_set_description(oc, XEN_ARM_PCIE_MEM_SIZE,
+        "Size of non-prefetchable memory of virtual PCIe host bridge");
+
+    object_class_property_add(oc, XEN_ARM_PCIE_PREFETCH_BASE, "uint64_t",
+                              xen_arm_get_pcie_prop,
+                              xen_arm_set_pcie_prop, NULL, NULL);
+    object_class_property_set_description(oc, XEN_ARM_PCIE_PREFETCH_BASE,
+        "Base address for prefetchable memory of virtual PCIe host bridge");
+    object_class_property_add(oc, XEN_ARM_PCIE_PREFETCH_SIZE, "uint64_t",
+                              xen_arm_get_pcie_prop,
+                              xen_arm_set_pcie_prop, NULL, NULL);
+    object_class_property_set_description(oc, XEN_ARM_PCIE_PREFETCH_SIZE,
+        "Size of prefetchable memory of virtual PCIe host bridge");
+
+    object_class_property_add(oc, XEN_ARM_PCIE_IRQ_BASE, "int",
+                              xen_arm_get_pcie_irq_base,
+                              xen_arm_set_pcie_irq_base, NULL, NULL);
+    object_class_property_set_description(oc, XEN_ARM_PCIE_IRQ_BASE,
+        "Number of first PCI legacy interrupt for PCIe host bridge");
 }
 
 static const TypeInfo xen_arm_machine_type = {
diff --git a/hw/xen/xen-hvm-common.c b/hw/xen/xen-hvm-common.c
index 2e7897dbd2..19fcccdb16 100644
--- a/hw/xen/xen-hvm-common.c
+++ b/hw/xen/xen-hvm-common.c
@@ -47,6 +47,8 @@ void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, MemoryRegion *mr,
     g_free(pfn_list);
 }
 
+uint16_t xen_pci_segment;
+
 static void xen_set_memory(struct MemoryListener *listener,
                            MemoryRegionSection *section,
                            bool add)
@@ -382,7 +384,12 @@ static void cpu_ioreq_config(XenIOState *state, ioreq_t *req)
     }
 
     QLIST_FOREACH(xendev, &state->dev_list, entry) {
-        if (xendev->sbdf != sbdf) {
+        /*
+         * As we append xen_pci_segment just before forming dm_op in
+         * xen_map_pcidev() we need to check with appended xen_pci_segment
+         * here as well.
+         */
+        if ((xendev->sbdf | (xen_pci_segment << 16)) != sbdf) {
             continue;
         }
 
diff --git a/include/hw/xen/xen_native.h b/include/hw/xen/xen_native.h
index 6f09c48823..2b1debaff4 100644
--- a/include/hw/xen/xen_native.h
+++ b/include/hw/xen/xen_native.h
@@ -431,6 +431,8 @@ static inline void xen_unmap_io_section(domid_t dom,
                                                     0, start_addr, end_addr);
 }
 
+extern uint16_t xen_pci_segment;
+
 static inline void xen_map_pcidev(domid_t dom,
                                   ioservid_t ioservid,
                                   PCIDevice *pci_dev)
@@ -441,7 +443,8 @@ static inline void xen_map_pcidev(domid_t dom,
 
     trace_xen_map_pcidev(ioservid, pci_dev_bus_num(pci_dev),
                          PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn));
-    xendevicemodel_map_pcidev_to_ioreq_server(xen_dmod, dom, ioservid, 0,
+    xendevicemodel_map_pcidev_to_ioreq_server(xen_dmod, dom, ioservid,
+                                              xen_pci_segment,
                                               pci_dev_bus_num(pci_dev),
                                               PCI_SLOT(pci_dev->devfn),
                                               PCI_FUNC(pci_dev->devfn));
@@ -457,7 +460,8 @@ static inline void xen_unmap_pcidev(domid_t dom,
 
     trace_xen_unmap_pcidev(ioservid, pci_dev_bus_num(pci_dev),
                            PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn));
-    xendevicemodel_unmap_pcidev_from_ioreq_server(xen_dmod, dom, ioservid, 0,
+    xendevicemodel_unmap_pcidev_from_ioreq_server(xen_dmod, dom, ioservid,
+                                                  xen_pci_segment,
                                                   pci_dev_bus_num(pci_dev),
                                                   PCI_SLOT(pci_dev->devfn),
                                                   PCI_FUNC(pci_dev->devfn));
