diff --git a/xen/arch/arm/gic-its.c b/xen/arch/arm/gic-its.c
index b52dff3..40238a2 100644
--- a/xen/arch/arm/gic-its.c
+++ b/xen/arch/arm/gic-its.c
@@ -21,6 +21,7 @@
 #include <xen/device_tree.h>
 #include <xen/libfdt/libfdt.h>
 #include <asm/p2m.h>
+#include <asm/io.h>
 #include <asm/gic.h>
 #include <asm/gic_v3_defs.h>
 #include <asm/gic-its.h>
@@ -38,6 +39,119 @@ static DEFINE_PER_CPU(void *, pending_table);
         min_t(unsigned int, lpi_data.host_lpi_bits, CONFIG_HOST_LPI_BITS)
 #define MAX_HOST_LPIS   (BIT(MAX_HOST_LPI_BITS) - 8192)
 
+#define BASER_ATTR_MASK                                           \
+        ((0x3UL << GITS_BASER_SHAREABILITY_SHIFT)               | \
+         (0x7UL << GITS_BASER_OUTER_CACHEABILITY_SHIFT)         | \
+         (0x7UL << GITS_BASER_INNER_CACHEABILITY_SHIFT))
+#define BASER_RO_MASK   (GENMASK(52, 48) | GENMASK(58, 56))
+
+static uint64_t encode_phys_addr(paddr_t addr, int page_bits)
+{
+    uint64_t ret;
+
+    if ( page_bits < 16)
+        return (uint64_t)addr & GENMASK(47, page_bits);
+
+    ret = addr & GENMASK(47, 16);
+    return ret | (addr & GENMASK(51, 48)) >> (48 - 12);
+}
+
+static int gicv3_map_baser(void __iomem *basereg, uint64_t regc, int nr_items)
+{
+    uint64_t attr;
+    int entry_size = (regc >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f;
+    int pagesz;
+    int order;
+    void *buffer = NULL;
+
+    attr  = GIC_BASER_InnerShareable << GITS_BASER_SHAREABILITY_SHIFT;
+    attr |= GIC_BASER_CACHE_SameAsInner << GITS_BASER_OUTER_CACHEABILITY_SHIFT;
+    attr |= GIC_BASER_CACHE_RaWaWb << GITS_BASER_INNER_CACHEABILITY_SHIFT;
+
+    /*
+     * Loop over the page sizes (4K, 16K, 64K) to find out what the host
+     * supports.
+     */
+    for (pagesz = 0; pagesz < 3; pagesz++)
+    {
+        uint64_t reg;
+        int nr_bytes;
+
+        nr_bytes = ROUNDUP(nr_items * entry_size, BIT(pagesz * 2 + 12));
+        order = get_order_from_bytes(nr_bytes);
+
+        if ( !buffer )
+            buffer = alloc_xenheap_pages(order, 0);
+        if ( !buffer )
+            return -ENOMEM;
+
+        reg  = attr;
+        reg |= (pagesz << GITS_BASER_PAGE_SIZE_SHIFT);
+        reg |= nr_bytes >> (pagesz * 2 + 12);
+        reg |= regc & BASER_RO_MASK;
+        reg |= GITS_BASER_VALID;
+        reg |= encode_phys_addr(virt_to_maddr(buffer), pagesz * 2 + 12);
+
+        writeq_relaxed(reg, basereg);
+        regc = readl_relaxed(basereg);
+
+        /* The host didn't like our attributes, just use what it returned. */
+        if ( (regc & BASER_ATTR_MASK) != attr )
+            attr = regc & BASER_ATTR_MASK;
+
+        /* If the host accepted our page size, we are done. */
+        if ( (reg & (3UL << GITS_BASER_PAGE_SIZE_SHIFT)) == pagesz )
+            return 0;
+
+        /* Check whether our buffer is aligned to the next page size already. */
+        if ( !(virt_to_maddr(buffer) & (BIT(pagesz * 2 + 12 + 2) - 1)) )
+        {
+            free_xenheap_pages(buffer, order);
+            buffer = NULL;
+        }
+    }
+
+    if ( buffer )
+        free_xenheap_pages(buffer, order);
+
+    return -EINVAL;
+}
+
+int gicv3_its_init(struct host_its *hw_its)
+{
+    uint64_t reg;
+    int i;
+
+    hw_its->its_base = ioremap_nocache(hw_its->addr, hw_its->size);
+    if ( !hw_its->its_base )
+        return -ENOMEM;
+
+    for (i = 0; i < 8; i++)
+    {
+        void __iomem *basereg = hw_its->its_base + GITS_BASER0 + i * 8;
+        int type;
+
+        reg = readq_relaxed(basereg);
+        type = (reg >> 56) & 0x7;
+        switch ( type )
+        {
+        case GITS_BASER_TYPE_NONE:
+            continue;
+        case GITS_BASER_TYPE_DEVICE:
+            /* TODO: find some better way of limiting the number of devices */
+            gicv3_map_baser(basereg, reg, 1024);
+            break;
+        case GITS_BASER_TYPE_COLLECTION:
+            gicv3_map_baser(basereg, reg, NR_CPUS);
+            break;
+        default:
+            continue;
+        }
+    }
+
+    return 0;
+}
+
 uint64_t gicv3_lpi_allocate_pendtable(void)
 {
     uint64_t reg, attr;
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 2534aa5..5cf4618 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -29,6 +29,7 @@
 #include <xen/irq.h>
 #include <xen/iocap.h>
 #include <xen/sched.h>
+#include <xen/err.h>
 #include <xen/errno.h>
 #include <xen/delay.h>
 #include <xen/device_tree.h>
@@ -1548,6 +1549,7 @@ static int __init gicv3_init(void)
 {
     int res, i;
     uint32_t reg;
+    struct host_its *hw_its;
 
     if ( !cpu_has_gicv3 )
     {
@@ -1603,6 +1605,9 @@ static int __init gicv3_init(void)
     res = gicv3_cpu_init();
     gicv3_hyp_init();
 
+    list_for_each_entry(hw_its, &host_its_list, entry)
+        gicv3_its_init(hw_its);
+
     spin_unlock(&gicv3.lock);
 
     return res;
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 48c6c78..589b889 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -18,6 +18,47 @@
 #ifndef __ASM_ARM_ITS_H__
 #define __ASM_ARM_ITS_H__
 
+#define LPI_OFFSET      8192
+
+#define GITS_CTLR       (0x000)
+#define GITS_IIDR       (0x004)
+#define GITS_TYPER      (0x008)
+#define GITS_CBASER     (0x080)
+#define GITS_CWRITER    (0x088)
+#define GITS_CREADR     (0x090)
+#define GITS_BASER0     (0x100)
+#define GITS_BASER1     (0x108)
+#define GITS_BASER2     (0x110)
+#define GITS_BASER3     (0x118)
+#define GITS_BASER4     (0x120)
+#define GITS_BASER5     (0x128)
+#define GITS_BASER6     (0x130)
+#define GITS_BASER7     (0x138)
+
+/* Register bits */
+#define GITS_CTLR_ENABLE     0x1
+#define GITS_IIDR_VALUE      0x34c
+
+#define GITS_BASER_VALID                BIT(63)
+#define GITS_BASER_INDIRECT             BIT(62)
+#define GITS_BASER_INNER_CACHEABILITY_SHIFT        59
+#define GITS_BASER_TYPE_SHIFT           56
+#define GITS_BASER_OUTER_CACHEABILITY_SHIFT        53
+#define GITS_BASER_TYPE_NONE            0UL
+#define GITS_BASER_TYPE_DEVICE          1UL
+#define GITS_BASER_TYPE_VCPU            2UL
+#define GITS_BASER_TYPE_CPU             3UL
+#define GITS_BASER_TYPE_COLLECTION      4UL
+#define GITS_BASER_TYPE_RESERVED5       5UL
+#define GITS_BASER_TYPE_RESERVED6       6UL
+#define GITS_BASER_TYPE_RESERVED7       7UL
+#define GITS_BASER_ENTRY_SIZE_SHIFT     48
+#define GITS_BASER_SHAREABILITY_SHIFT   10
+#define GITS_BASER_PAGE_SIZE_SHIFT      8
+#define GITS_BASER_RO_MASK              ((7UL << GITS_BASER_TYPE_SHIFT) | \
+                                        (31UL << GITS_BASER_ENTRY_SIZE_SHIFT) |\
+                                        GITS_BASER_INDIRECT)
+
 #ifndef __ASSEMBLY__
 #include <xen/device_tree.h>
 
@@ -27,6 +68,7 @@ struct host_its {
     const struct dt_device_node *dt_node;
     paddr_t addr;
     paddr_t size;
+    void __iomem *its_base;
 };
 
 extern struct list_head host_its_list;
@@ -42,8 +84,9 @@ void gicv3_its_dt_init(const struct dt_device_node *node);
 uint64_t gicv3_lpi_get_proptable(void);
 uint64_t gicv3_lpi_allocate_pendtable(void);
 
-/* Initialize the host structures for LPIs. */
+/* Initialize the host structures for LPIs and the host ITSes. */
 int gicv3_lpi_init_host_lpis(int nr_lpis);
+int gicv3_its_init(struct host_its *hw_its);
 
 #else
 
@@ -62,6 +105,10 @@ static inline int gicv3_lpi_init_host_lpis(int nr_lpis)
 {
     return 0;
 }
+static inline int gicv3_its_init(struct host_its *hw_its)
+{
+    return 0;
+}
 #endif /* CONFIG_HAS_ITS */
 
 #endif /* __ASSEMBLY__ */
