[Xen-devel,RFC,28/49] ARM: new VGIC: Add GICv2 MMIO handling framework

Message ID 20180209143937.28866-29-andre.przywara@linaro.org
State New
Headers show
Series
  • New VGIC(-v2) implementation
Related show

Commit Message

Andre Przywara Feb. 9, 2018, 2:39 p.m.
Create vgic-mmio-v2.c to describe GICv2 emulation specific handlers
using the initializer macros provided by the VGIC MMIO framework.
Provide a function to register the GICv2 distributor registers to
the Xen MMIO framework.
The actual handler functions are still stubs in this patch.

This is based on Linux commit fb848db39661, written by Andre Przywara.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
 xen/arch/arm/vgic/vgic-mmio-v2.c | 83 ++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic-mmio.c    | 26 +++++++++++++
 xen/arch/arm/vgic/vgic-mmio.h    |  2 +
 xen/arch/arm/vgic/vgic.h         |  2 +
 4 files changed, 113 insertions(+)
 create mode 100644 xen/arch/arm/vgic/vgic-mmio-v2.c

Comments

Julien Grall Feb. 16, 2018, 3:39 p.m. | #1
Hi Andre,

On 09/02/18 14:39, Andre Przywara wrote:
> Create vgic-mmio-v2.c to describe GICv2 emulation specific handlers
> using the initializer macros provided by the VGIC MMIO framework.
> Provide a function to register the GICv2 distributor registers to
> the Xen MMIO framework.
> The actual handler functions are still stubs in this patch.
> 
> This is based on Linux commit fb848db39661, written by Andre Przywara.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> ---
>   xen/arch/arm/vgic/vgic-mmio-v2.c | 83 ++++++++++++++++++++++++++++++++++++++++
>   xen/arch/arm/vgic/vgic-mmio.c    | 26 +++++++++++++
>   xen/arch/arm/vgic/vgic-mmio.h    |  2 +
>   xen/arch/arm/vgic/vgic.h         |  2 +
>   4 files changed, 113 insertions(+)
>   create mode 100644 xen/arch/arm/vgic/vgic-mmio-v2.c
> 
> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
> new file mode 100644
> index 0000000000..ee685a5a07
> --- /dev/null
> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
> @@ -0,0 +1,83 @@
> +/*
> + * VGICv2 MMIO handling functions
> + * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <xen/bitops.h>
> +#include <xen/sched.h>
> +#include <xen/sizes.h>
> +#include <asm/arm_vgic.h>
> +
> +#include "vgic.h"
> +#include "vgic-mmio.h"
> +
> +static const struct vgic_register_region vgic_v2_dist_registers[] = {
> +    REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 12,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IGROUPR,
> +        vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISENABLER,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICENABLER,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISPENDR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICPENDR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISACTIVER,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICACTIVER,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IPRIORITYR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
> +        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ITARGETSR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
> +        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICFGR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 2,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_LENGTH(GICD_SGIR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_LENGTH(GICD_CPENDSGIR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
> +        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
> +    REGISTER_DESC_WITH_LENGTH(GICD_SPENDSGIR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
> +        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
> +};
> +
> +unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
> +{
> +    dev->regions = vgic_v2_dist_registers;
> +    dev->nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
> +
> +    return SZ_4K;
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
> index 3c70945466..59703a6909 100644
> --- a/xen/arch/arm/vgic/vgic-mmio.c
> +++ b/xen/arch/arm/vgic/vgic-mmio.c
> @@ -182,6 +182,32 @@ struct mmio_handler_ops xen_io_gic_ops = {
>       .write = dispatch_mmio_write,
>   };
>   
> +int vgic_register_dist_iodev(struct domain *d, paddr_t dist_base_address,

I would rather prefer to use gfn_t over paddr_t. The former deal with 
frame only is safer to use.

> +                 enum vgic_type type)
> +{
> +    struct vgic_io_device *io_device = &d->arch.vgic.dist_iodev;
> +    int ret = 0;

This variable is pointless. You never set it after so always return 0.

> +    unsigned int len;
> +
> +    switch (type)

switch ( ... )

> +    {
> +    case VGIC_V2:
> +        len = vgic_v2_init_dist_iodev(io_device);
> +        break;
> +    default:
> +        BUG_ON(1);

Please use BUG() here. But have you checked we will never reach here 
with the wrong vgic_type?

> +    }
> +
> +    io_device->base_addr = dist_base_address;

Also base_addr & co would only contain frame.

> +    io_device->iodev_type = IODEV_DIST;
> +    io_device->redist_vcpu = NULL;
> +
> +    register_mmio_handler(d, &xen_io_gic_ops, dist_base_address, len,
> +                  io_device);
> +
> +    return ret;
> +}
> +
>   /*
>    * Local variables:
>    * mode: C
> diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
> index 375b70561d..10ac682296 100644
> --- a/xen/arch/arm/vgic/vgic-mmio.h
> +++ b/xen/arch/arm/vgic/vgic-mmio.h
> @@ -137,6 +137,8 @@ unsigned long vgic_mmio_read_rao(struct vcpu *vcpu,
>   void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
>                           unsigned int len, unsigned long val);
>   
> +unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
> +
>   /* Find the proper register handler entry given a certain address offset */
>   const struct vgic_register_region *
>   vgic_find_mmio_region(const struct vgic_register_region *regions,
> diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
> index 426b34d0ce..7747d3f3e0 100644
> --- a/xen/arch/arm/vgic/vgic.h
> +++ b/xen/arch/arm/vgic/vgic.h
> @@ -49,6 +49,8 @@ void vgic_v2_fold_lr_state(struct vcpu *vcpu);
>   void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr);
>   void vgic_v2_clear_lr(struct vcpu *vcpu, int lr);
>   void vgic_v2_set_underflow(struct vcpu *vcpu);
> +int vgic_register_dist_iodev(struct domain *d, paddr_t dist_base_address,
> +                 enum vgic_type);
>   
>   void vgic_v2_save_state(struct vcpu *vcpu);
>   void vgic_v2_restore_state(struct vcpu *vcpu);
> 

Cheers,
Andre Przywara Feb. 19, 2018, 12:23 p.m. | #2
Hi,

On 16/02/18 15:39, Julien Grall wrote:
> Hi Andre,
> 
> On 09/02/18 14:39, Andre Przywara wrote:
>> Create vgic-mmio-v2.c to describe GICv2 emulation specific handlers
>> using the initializer macros provided by the VGIC MMIO framework.
>> Provide a function to register the GICv2 distributor registers to
>> the Xen MMIO framework.
>> The actual handler functions are still stubs in this patch.
>>
>> This is based on Linux commit fb848db39661, written by Andre Przywara.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> ---
>>   xen/arch/arm/vgic/vgic-mmio-v2.c | 83
>> ++++++++++++++++++++++++++++++++++++++++
>>   xen/arch/arm/vgic/vgic-mmio.c    | 26 +++++++++++++
>>   xen/arch/arm/vgic/vgic-mmio.h    |  2 +
>>   xen/arch/arm/vgic/vgic.h         |  2 +
>>   4 files changed, 113 insertions(+)
>>   create mode 100644 xen/arch/arm/vgic/vgic-mmio-v2.c
>>
>> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c
>> b/xen/arch/arm/vgic/vgic-mmio-v2.c
>> new file mode 100644
>> index 0000000000..ee685a5a07
>> --- /dev/null
>> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
>> @@ -0,0 +1,83 @@
>> +/*
>> + * VGICv2 MMIO handling functions
>> + * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <xen/bitops.h>
>> +#include <xen/sched.h>
>> +#include <xen/sizes.h>
>> +#include <asm/arm_vgic.h>
>> +
>> +#include "vgic.h"
>> +#include "vgic-mmio.h"
>> +
>> +static const struct vgic_register_region vgic_v2_dist_registers[] = {
>> +    REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 12,
>> +        VGIC_ACCESS_32bit),
>> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IGROUPR,
>> +        vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
>> +        VGIC_ACCESS_32bit),
>> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISENABLER,
>> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
>> +        VGIC_ACCESS_32bit),
>> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICENABLER,
>> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
>> +        VGIC_ACCESS_32bit),
>> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISPENDR,
>> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
>> +        VGIC_ACCESS_32bit),
>> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICPENDR,
>> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
>> +        VGIC_ACCESS_32bit),
>> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISACTIVER,
>> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
>> +        VGIC_ACCESS_32bit),
>> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICACTIVER,
>> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
>> +        VGIC_ACCESS_32bit),
>> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IPRIORITYR,
>> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
>> +        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ITARGETSR,
>> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
>> +        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICFGR,
>> +        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 2,
>> +        VGIC_ACCESS_32bit),
>> +    REGISTER_DESC_WITH_LENGTH(GICD_SGIR,
>> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
>> +        VGIC_ACCESS_32bit),
>> +    REGISTER_DESC_WITH_LENGTH(GICD_CPENDSGIR,
>> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
>> +        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>> +    REGISTER_DESC_WITH_LENGTH(GICD_SPENDSGIR,
>> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
>> +        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>> +};
>> +
>> +unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>> +{
>> +    dev->regions = vgic_v2_dist_registers;
>> +    dev->nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>> +
>> +    return SZ_4K;
>> +}
>> +
>> +/*
>> + * Local variables:
>> + * mode: C
>> + * c-file-style: "BSD"
>> + * c-basic-offset: 4
>> + * indent-tabs-mode: nil
>> + * End:
>> + */
>> diff --git a/xen/arch/arm/vgic/vgic-mmio.c
>> b/xen/arch/arm/vgic/vgic-mmio.c
>> index 3c70945466..59703a6909 100644
>> --- a/xen/arch/arm/vgic/vgic-mmio.c
>> +++ b/xen/arch/arm/vgic/vgic-mmio.c
>> @@ -182,6 +182,32 @@ struct mmio_handler_ops xen_io_gic_ops = {
>>       .write = dispatch_mmio_write,
>>   };
>>   +int vgic_register_dist_iodev(struct domain *d, paddr_t
>> dist_base_address,
> 
> I would rather prefer to use gfn_t over paddr_t. The former deal with
> frame only is safer to use.

OK.

>> +                 enum vgic_type type)
>> +{
>> +    struct vgic_io_device *io_device = &d->arch.vgic.dist_iodev;
>> +    int ret = 0;
> 
> This variable is pointless. You never set it after so always return 0.

True. The KVM version of register_mmio_handler() returns an error value,
which is held in this variable (since it is called within a lock). Will
remove it.

>> +    unsigned int len;
>> +
>> +    switch (type)
> 
> switch ( ... )
> 
>> +    {
>> +    case VGIC_V2:
>> +        len = vgic_v2_init_dist_iodev(io_device);
>> +        break;
>> +    default:
>> +        BUG_ON(1);
> 
> Please use BUG() here. But have you checked we will never reach here
> with the wrong vgic_type?

This is just a placeholder for now, the proper vGICv3 function will plug
in later. Actually I don't expect this line to be ever part of running code.
Even if, at the moment no one sets the type to anything other than
VGIC_V2, so this should be safe.

Cheers,
Andre.

>> +    }
>> +
>> +    io_device->base_addr = dist_base_address;
> 
> Also base_addr & co would only contain frame.
> 
>> +    io_device->iodev_type = IODEV_DIST;
>> +    io_device->redist_vcpu = NULL;
>> +
>> +    register_mmio_handler(d, &xen_io_gic_ops, dist_base_address, len,
>> +                  io_device);
>> +
>> +    return ret;
>> +}
>> +
>>   /*
>>    * Local variables:
>>    * mode: C
>> diff --git a/xen/arch/arm/vgic/vgic-mmio.h
>> b/xen/arch/arm/vgic/vgic-mmio.h
>> index 375b70561d..10ac682296 100644
>> --- a/xen/arch/arm/vgic/vgic-mmio.h
>> +++ b/xen/arch/arm/vgic/vgic-mmio.h
>> @@ -137,6 +137,8 @@ unsigned long vgic_mmio_read_rao(struct vcpu *vcpu,
>>   void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
>>                           unsigned int len, unsigned long val);
>>   +unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>> +
>>   /* Find the proper register handler entry given a certain address
>> offset */
>>   const struct vgic_register_region *
>>   vgic_find_mmio_region(const struct vgic_register_region *regions,
>> diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
>> index 426b34d0ce..7747d3f3e0 100644
>> --- a/xen/arch/arm/vgic/vgic.h
>> +++ b/xen/arch/arm/vgic/vgic.h
>> @@ -49,6 +49,8 @@ void vgic_v2_fold_lr_state(struct vcpu *vcpu);
>>   void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq,
>> int lr);
>>   void vgic_v2_clear_lr(struct vcpu *vcpu, int lr);
>>   void vgic_v2_set_underflow(struct vcpu *vcpu);
>> +int vgic_register_dist_iodev(struct domain *d, paddr_t
>> dist_base_address,
>> +                 enum vgic_type);
>>     void vgic_v2_save_state(struct vcpu *vcpu);
>>   void vgic_v2_restore_state(struct vcpu *vcpu);
>>
> 
> Cheers,
>

Patch

diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
new file mode 100644
index 0000000000..ee685a5a07
--- /dev/null
+++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
@@ -0,0 +1,83 @@ 
+/*
+ * VGICv2 MMIO handling functions
+ * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/bitops.h>
+#include <xen/sched.h>
+#include <xen/sizes.h>
+#include <asm/arm_vgic.h>
+
+#include "vgic.h"
+#include "vgic-mmio.h"
+
+static const struct vgic_register_region vgic_v2_dist_registers[] = {
+    REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 12,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IGROUPR,
+        vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISENABLER,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICENABLER,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISPENDR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICPENDR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISACTIVER,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICACTIVER,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IPRIORITYR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
+        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ITARGETSR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
+        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICFGR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 2,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_LENGTH(GICD_SGIR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_LENGTH(GICD_CPENDSGIR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
+        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
+    REGISTER_DESC_WITH_LENGTH(GICD_SPENDSGIR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
+        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
+};
+
+unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
+{
+    dev->regions = vgic_v2_dist_registers;
+    dev->nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
+
+    return SZ_4K;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
index 3c70945466..59703a6909 100644
--- a/xen/arch/arm/vgic/vgic-mmio.c
+++ b/xen/arch/arm/vgic/vgic-mmio.c
@@ -182,6 +182,32 @@  struct mmio_handler_ops xen_io_gic_ops = {
     .write = dispatch_mmio_write,
 };
 
+int vgic_register_dist_iodev(struct domain *d, paddr_t dist_base_address,
+                 enum vgic_type type)
+{
+    struct vgic_io_device *io_device = &d->arch.vgic.dist_iodev;
+    int ret = 0;
+    unsigned int len;
+
+    switch (type)
+    {
+    case VGIC_V2:
+        len = vgic_v2_init_dist_iodev(io_device);
+        break;
+    default:
+        BUG_ON(1);
+    }
+
+    io_device->base_addr = dist_base_address;
+    io_device->iodev_type = IODEV_DIST;
+    io_device->redist_vcpu = NULL;
+
+    register_mmio_handler(d, &xen_io_gic_ops, dist_base_address, len,
+                  io_device);
+
+    return ret;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
index 375b70561d..10ac682296 100644
--- a/xen/arch/arm/vgic/vgic-mmio.h
+++ b/xen/arch/arm/vgic/vgic-mmio.h
@@ -137,6 +137,8 @@  unsigned long vgic_mmio_read_rao(struct vcpu *vcpu,
 void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
                         unsigned int len, unsigned long val);
 
+unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
+
 /* Find the proper register handler entry given a certain address offset */
 const struct vgic_register_region *
 vgic_find_mmio_region(const struct vgic_register_region *regions,
diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
index 426b34d0ce..7747d3f3e0 100644
--- a/xen/arch/arm/vgic/vgic.h
+++ b/xen/arch/arm/vgic/vgic.h
@@ -49,6 +49,8 @@  void vgic_v2_fold_lr_state(struct vcpu *vcpu);
 void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_clear_lr(struct vcpu *vcpu, int lr);
 void vgic_v2_set_underflow(struct vcpu *vcpu);
+int vgic_register_dist_iodev(struct domain *d, paddr_t dist_base_address,
+                 enum vgic_type);
 
 void vgic_v2_save_state(struct vcpu *vcpu);
 void vgic_v2_restore_state(struct vcpu *vcpu);