Package: qemu-system-arm
Version: 1:2.4+dfsg-3
Severity: wishlist
Tags: patch

ARM systems with GICv3 support (such as Cavium Thunder) need a QEMU
that supports vGICv3 to work with KVM. This feature has landed
upstream recently - attached is a backport that applies to Debian.
diff -Nru qemu-2.4+dfsg/debian/changelog qemu-2.4+dfsg/debian/changelog
--- qemu-2.4+dfsg/debian/changelog	2015-09-15 10:30:33.000000000 -0600
+++ qemu-2.4+dfsg/debian/changelog	2015-10-06 17:05:59.000000000 -0600
@@ -1,3 +1,9 @@
+qemu (1:2.4+dfsg-3+vgicv3.1) UNRELEASED; urgency=medium
+
+  * Backport vGICv3 support.
+
+ -- dann frazier <da...@debian.org>  Tue, 06 Oct 2015 17:05:20 -0600
+
 qemu (1:2.4+dfsg-3) unstable; urgency=high
 
   * ne2000-add-checks-to-validate-ring-buffer-pointers-CVE-2015-5279.patch
diff -Nru qemu-2.4+dfsg/debian/patches/arm_kvm-Do-not-assume-particular-GIC-type-in-kvm_arc.patch qemu-2.4+dfsg/debian/patches/arm_kvm-Do-not-assume-particular-GIC-type-in-kvm_arc.patch
--- qemu-2.4+dfsg/debian/patches/arm_kvm-Do-not-assume-particular-GIC-type-in-kvm_arc.patch	1969-12-31 17:00:00.000000000 -0700
+++ qemu-2.4+dfsg/debian/patches/arm_kvm-Do-not-assume-particular-GIC-type-in-kvm_arc.patch	2015-10-06 16:42:41.000000000 -0600
@@ -0,0 +1,82 @@
+From 34e85cd9173816cd48f5578c7838c26afbe592c4 Mon Sep 17 00:00:00 2001
+From: Pavel Fedin <p.fe...@samsung.com>
+Date: Thu, 24 Sep 2015 01:29:37 +0100
+Subject: [PATCH 25/27] arm_kvm: Do not assume particular GIC type in
+ kvm_arch_irqchip_create()
+
+This allows us to use different GIC types from v2. There are no kernels
+which could advertise KVM_CAP_DEVICE_CTRL without the actual ability to
+create GIC with it.
+
+GIC version probe code moved to kvm_arm_vgic_probe() which will be used
+later.
+
+Signed-off-by: Pavel Fedin <p.fe...@samsung.com>
+Reviewed-by: Eric Auger <eric.au...@linaro.org>
+Tested-by: Ashok kumar <ash...@broadcom.com>
+Reviewed-by: Peter Maydell <peter.mayd...@linaro.org>
+Message-id: 015f4d9e4a8a50dfbdd734c4730558e24a69c6dc.1441784344.git.p.fe...@samsung.com
+Signed-off-by: Peter Maydell <peter.mayd...@linaro.org>
+---
+ target-arm/kvm.c     | 19 ++++++++++++-------
+ target-arm/kvm_arm.h |  9 +++++++++
+ 2 files changed, 21 insertions(+), 7 deletions(-)
+
+diff --git a/target-arm/kvm.c b/target-arm/kvm.c
+index b278542..6aadcd8 100644
+--- a/target-arm/kvm.c
++++ b/target-arm/kvm.c
+@@ -585,18 +585,23 @@ void kvm_arch_init_irq_routing(KVMState *s)
+ 
+ int kvm_arch_irqchip_create(KVMState *s)
+ {
+-    int ret;
+-
+     /* If we can create the VGIC using the newer device control API, we
+      * let the device do this when it initializes itself, otherwise we
+      * fall back to the old API */
++    return kvm_check_extension(s, KVM_CAP_DEVICE_CTRL);
++}
+ 
+-    ret = kvm_create_device(s, KVM_DEV_TYPE_ARM_VGIC_V2, true);
+-    if (ret == 0) {
+-        return 1;
++int kvm_arm_vgic_probe(void)
++{
++    if (kvm_create_device(kvm_state,
++                          KVM_DEV_TYPE_ARM_VGIC_V3, true) == 0) {
++        return 3;
++    } else if (kvm_create_device(kvm_state,
++                                 KVM_DEV_TYPE_ARM_VGIC_V2, true) == 0) {
++        return 2;
++    } else {
++        return 0;
+     }
+-
+-    return 0;
+ }
+ 
+ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
+diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h
+index b3e0ab7..10ce771 100644
+--- a/target-arm/kvm_arm.h
++++ b/target-arm/kvm_arm.h
+@@ -189,6 +189,15 @@ int kvm_arm_sync_mpstate_to_kvm(ARMCPU *cpu);
+  */
+ int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu);
+ 
++int kvm_arm_vgic_probe(void);
++
++#else
++
++static inline int kvm_arm_vgic_probe(void)
++{
++    return 0;
++}
++
+ #endif
+ 
+ static inline const char *gic_class_name(void)
+-- 
+2.6.0
+
diff -Nru qemu-2.4+dfsg/debian/patches/hw-arm-gic-Kill-code-duplication.patch qemu-2.4+dfsg/debian/patches/hw-arm-gic-Kill-code-duplication.patch
--- qemu-2.4+dfsg/debian/patches/hw-arm-gic-Kill-code-duplication.patch	1969-12-31 17:00:00.000000000 -0700
+++ qemu-2.4+dfsg/debian/patches/hw-arm-gic-Kill-code-duplication.patch	2015-10-06 16:44:42.000000000 -0600
@@ -0,0 +1,257 @@
+From 7926c210ab0c44fc3612461a50f487d16be98dca Mon Sep 17 00:00:00 2001
+From: Pavel Fedin <p.fe...@samsung.com>
+Date: Thu, 13 Aug 2015 11:26:21 +0100
+Subject: [PATCH 2/3] hw/arm/gic: Kill code duplication
+
+Extracted duplicated initialization code from SW-emulated and KVM GIC
+implementations and put into gic_init_irqs_and_mmio()
+
+Signed-off-by: Pavel Fedin <p.fe...@samsung.com>
+Message-id: 8ea5b2781ef39cb5989420987fc73c70e377687d.1438758065.git.p.fe...@samsung.com
+Reviewed-by: Peter Maydell <peter.mayd...@linaro.org>
+Signed-off-by: Peter Maydell <peter.mayd...@linaro.org>
+---
+ hw/intc/arm_gic.c                | 64 ++++++++++++----------------------------
+ hw/intc/arm_gic_common.c         | 41 +++++++++++++++++++++++++
+ hw/intc/arm_gic_kvm.c            | 28 +-----------------
+ include/hw/intc/arm_gic_common.h |  3 ++
+ 4 files changed, 64 insertions(+), 72 deletions(-)
+
+Index: qemu-2.4+dfsg/hw/intc/arm_gic.c
+===================================================================
+--- qemu-2.4+dfsg.orig/hw/intc/arm_gic.c
++++ qemu-2.4+dfsg/hw/intc/arm_gic.c
+@@ -922,12 +922,6 @@ static MemTxResult gic_dist_write(void *
+     }
+ }
+ 
+-static const MemoryRegionOps gic_dist_ops = {
+-    .read_with_attrs = gic_dist_read,
+-    .write_with_attrs = gic_dist_write,
+-    .endianness = DEVICE_NATIVE_ENDIAN,
+-};
+-
+ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
+                                 uint64_t *data, MemTxAttrs attrs)
+ {
+@@ -1056,10 +1050,17 @@ static MemTxResult gic_do_cpu_write(void
+     return gic_cpu_write(s, id, addr, value, attrs);
+ }
+ 
+-static const MemoryRegionOps gic_thiscpu_ops = {
+-    .read_with_attrs = gic_thiscpu_read,
+-    .write_with_attrs = gic_thiscpu_write,
+-    .endianness = DEVICE_NATIVE_ENDIAN,
++static const MemoryRegionOps gic_ops[2] = {
++    {
++        .read_with_attrs = gic_dist_read,
++        .write_with_attrs = gic_dist_write,
++        .endianness = DEVICE_NATIVE_ENDIAN,
++    },
++    {
++        .read_with_attrs = gic_thiscpu_read,
++        .write_with_attrs = gic_thiscpu_write,
++        .endianness = DEVICE_NATIVE_ENDIAN,
++    }
+ };
+ 
+ static const MemoryRegionOps gic_cpu_ops = {
+@@ -1068,31 +1069,10 @@ static const MemoryRegionOps gic_cpu_ops
+     .endianness = DEVICE_NATIVE_ENDIAN,
+ };
+ 
++/* This function is used by nvic model */
+ void gic_init_irqs_and_distributor(GICState *s)
+ {
+-    SysBusDevice *sbd = SYS_BUS_DEVICE(s);
+-    int i;
+-
+-    i = s->num_irq - GIC_INTERNAL;
+-    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
+-     * GPIO array layout is thus:
+-     *  [0..N-1] SPIs
+-     *  [N..N+31] PPIs for CPU 0
+-     *  [N+32..N+63] PPIs for CPU 1
+-     *   ...
+-     */
+-    if (s->revision != REV_NVIC) {
+-        i += (GIC_INTERNAL * s->num_cpu);
+-    }
+-    qdev_init_gpio_in(DEVICE(s), gic_set_irq, i);
+-    for (i = 0; i < NUM_CPU(s); i++) {
+-        sysbus_init_irq(sbd, &s->parent_irq[i]);
+-    }
+-    for (i = 0; i < NUM_CPU(s); i++) {
+-        sysbus_init_irq(sbd, &s->parent_fiq[i]);
+-    }
+-    memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s,
+-                          "gic_dist", 0x1000);
++    gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops);
+ }
+ 
+ static void arm_gic_realize(DeviceState *dev, Error **errp)
+@@ -1110,28 +1090,22 @@ static void arm_gic_realize(DeviceState
+         return;
+     }
+ 
+-    gic_init_irqs_and_distributor(s);
++    /* This creates distributor and main CPU interface (s->cpuiomem[0]) */
++    gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops);
+ 
+-    /* Memory regions for the CPU interfaces (NVIC doesn't have these):
+-     * a region for "CPU interface for this core", then a region for
+-     * "CPU interface for core 0", "for core 1", ...
++    /* Extra core-specific regions for the CPU interfaces. This is
++     * necessary for "franken-GIC" implementations, for example on
++     * Exynos 4.
+      * NB that the memory region size of 0x100 applies for the 11MPCore
+      * and also cores following the GIC v1 spec (ie A9).
+      * GIC v2 defines a larger memory region (0x1000) so this will need
+      * to be extended when we implement A15.
+      */
+-    memory_region_init_io(&s->cpuiomem[0], OBJECT(s), &gic_thiscpu_ops, s,
+-                          "gic_cpu", 0x100);
+     for (i = 0; i < NUM_CPU(s); i++) {
+         s->backref[i] = s;
+         memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops,
+                               &s->backref[i], "gic_cpu", 0x100);
+-    }
+-    /* Distributor */
+-    sysbus_init_mmio(sbd, &s->iomem);
+-    /* cpu interfaces (one for "current cpu" plus one per cpu) */
+-    for (i = 0; i <= NUM_CPU(s); i++) {
+-        sysbus_init_mmio(sbd, &s->cpuiomem[i]);
++        sysbus_init_mmio(sbd, &s->cpuiomem[i+1]);
+     }
+ }
+ 
+Index: qemu-2.4+dfsg/hw/intc/arm_gic_common.c
+===================================================================
+--- qemu-2.4+dfsg.orig/hw/intc/arm_gic_common.c
++++ qemu-2.4+dfsg/hw/intc/arm_gic_common.c
+@@ -84,6 +84,47 @@ static const VMStateDescription vmstate_
+     }
+ };
+ 
++void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler,
++                            const MemoryRegionOps *ops)
++{
++    SysBusDevice *sbd = SYS_BUS_DEVICE(s);
++    int i = s->num_irq - GIC_INTERNAL;
++
++    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
++     * GPIO array layout is thus:
++     *  [0..N-1] SPIs
++     *  [N..N+31] PPIs for CPU 0
++     *  [N+32..N+63] PPIs for CPU 1
++     *   ...
++     */
++    if (s->revision != REV_NVIC) {
++        i += (GIC_INTERNAL * s->num_cpu);
++    }
++    qdev_init_gpio_in(DEVICE(s), handler, i);
++
++    for (i = 0; i < s->num_cpu; i++) {
++        sysbus_init_irq(sbd, &s->parent_irq[i]);
++    }
++    for (i = 0; i < s->num_cpu; i++) {
++        sysbus_init_irq(sbd, &s->parent_fiq[i]);
++    }
++
++    /* Distributor */
++    memory_region_init_io(&s->iomem, OBJECT(s), ops, s, "gic_dist", 0x1000);
++    sysbus_init_mmio(sbd, &s->iomem);
++
++    if (s->revision != REV_NVIC) {
++        /* This is the main CPU interface "for this core". It is always
++         * present because it is required by both software emulation and KVM.
++         * NVIC is not handled here because its CPU interface is different,
++         * neither it can use KVM.
++         */
++        memory_region_init_io(&s->cpuiomem[0], OBJECT(s), ops ? &ops[1] : NULL,
++                              s, "gic_cpu", s->revision == 2 ? 0x1000 : 0x100);
++        sysbus_init_mmio(sbd, &s->cpuiomem[0]);
++    }
++}
++
+ static void arm_gic_common_realize(DeviceState *dev, Error **errp)
+ {
+     GICState *s = ARM_GIC_COMMON(dev);
+Index: qemu-2.4+dfsg/hw/intc/arm_gic_kvm.c
+===================================================================
+--- qemu-2.4+dfsg.orig/hw/intc/arm_gic_kvm.c
++++ qemu-2.4+dfsg/hw/intc/arm_gic_kvm.c
+@@ -543,7 +543,6 @@ static void kvm_arm_gic_realize(DeviceSt
+ {
+     int i;
+     GICState *s = KVM_ARM_GIC(dev);
+-    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+     KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
+     Error *local_err = NULL;
+     int ret;
+@@ -560,32 +559,13 @@ static void kvm_arm_gic_realize(DeviceSt
+         return;
+     }
+ 
+-    i = s->num_irq - GIC_INTERNAL;
+-    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
+-     * GPIO array layout is thus:
+-     *  [0..N-1] SPIs
+-     *  [N..N+31] PPIs for CPU 0
+-     *  [N+32..N+63] PPIs for CPU 1
+-     *   ...
+-     */
+-    i += (GIC_INTERNAL * s->num_cpu);
+-    qdev_init_gpio_in(dev, kvm_arm_gic_set_irq, i);
++    gic_init_irqs_and_mmio(s, kvm_arm_gic_set_irq, NULL);
+ 
+     for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
+         qemu_irq irq = qdev_get_gpio_in(dev, i);
+         kvm_irqchip_set_qemuirq_gsi(kvm_state, irq, i);
+     }
+ 
+-    /* We never use our outbound IRQ/FIQ lines but provide them so that
+-     * we maintain the same interface as the non-KVM GIC.
+-     */
+-    for (i = 0; i < s->num_cpu; i++) {
+-        sysbus_init_irq(sbd, &s->parent_irq[i]);
+-    }
+-    for (i = 0; i < s->num_cpu; i++) {
+-        sysbus_init_irq(sbd, &s->parent_fiq[i]);
+-    }
+-
+     /* Try to create the device via the device control API */
+     s->dev_fd = -1;
+     ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V2, false);
+@@ -609,9 +589,6 @@ static void kvm_arm_gic_realize(DeviceSt
+     }
+ 
+     /* Distributor */
+-    memory_region_init_reservation(&s->iomem, OBJECT(s),
+-                                   "kvm-gic_dist", 0x1000);
+-    sysbus_init_mmio(sbd, &s->iomem);
+     kvm_arm_register_device(&s->iomem,
+                             (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
+                             | KVM_VGIC_V2_ADDR_TYPE_DIST,
+@@ -622,9 +599,6 @@ static void kvm_arm_gic_realize(DeviceSt
+      * provide the "interface for core #N" memory regions, because
+      * cores with a VGIC don't have those.
+      */
+-    memory_region_init_reservation(&s->cpuiomem[0], OBJECT(s),
+-                                   "kvm-gic_cpu", 0x1000);
+-    sysbus_init_mmio(sbd, &s->cpuiomem[0]);
+     kvm_arm_register_device(&s->cpuiomem[0],
+                             (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
+                             | KVM_VGIC_V2_ADDR_TYPE_CPU,
+Index: qemu-2.4+dfsg/include/hw/intc/arm_gic_common.h
+===================================================================
+--- qemu-2.4+dfsg.orig/include/hw/intc/arm_gic_common.h
++++ qemu-2.4+dfsg/include/hw/intc/arm_gic_common.h
+@@ -138,4 +138,7 @@ typedef struct ARMGICCommonClass {
+     void (*post_load)(GICState *s);
+ } ARMGICCommonClass;
+ 
++void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler,
++                            const MemoryRegionOps *ops);
++
+ #endif
diff -Nru qemu-2.4+dfsg/debian/patches/hw-arm-virt-Add-gic-version-option-to-virt-machine.patch qemu-2.4+dfsg/debian/patches/hw-arm-virt-Add-gic-version-option-to-virt-machine.patch
--- qemu-2.4+dfsg/debian/patches/hw-arm-virt-Add-gic-version-option-to-virt-machine.patch	1969-12-31 17:00:00.000000000 -0700
+++ qemu-2.4+dfsg/debian/patches/hw-arm-virt-Add-gic-version-option-to-virt-machine.patch	2015-10-06 16:49:06.000000000 -0600
@@ -0,0 +1,426 @@
+From b92ad3949bc9cacd1652b4e07e7f6003b9e512af Mon Sep 17 00:00:00 2001
+From: Pavel Fedin <p.fe...@samsung.com>
+Date: Thu, 24 Sep 2015 01:29:37 +0100
+Subject: [PATCH 27/27] hw/arm/virt: Add gic-version option to virt machine
+
+Add gic_version to VirtMachineState, set it to value of the option
+and pass it around where necessary. Instantiate devices and fdt
+nodes according to the choice.
+
+max_cpus for virt machine increased to 123 (calculated from redistributor
+space available in the memory map). GICv2 compatibility check happens
+inside arm_gic_common_realize().
+
+ITS region is added to the memory map too, however currently it not used,
+just reserved.
+
+Signed-off-by: Pavel Fedin <p.fe...@samsung.com>
+Tested-by: Ashok kumar <ash...@broadcom.com>
+[PMM: Added missing cpu_to_le* calls, thanks to Shannon Zhao]
+Reviewed-by: Peter Maydell <peter.mayd...@linaro.org>
+Signed-off-by: Peter Maydell <peter.mayd...@linaro.org>
+---
+ hw/arm/virt-acpi-build.c         |  54 ++++++++++-------
+ hw/arm/virt.c                    | 124 +++++++++++++++++++++++++++++++--------
+ include/hw/acpi/acpi-defs.h      |   9 +++
+ include/hw/arm/virt-acpi-build.h |   1 +
+ include/hw/arm/virt.h            |   4 +-
+ 5 files changed, 146 insertions(+), 46 deletions(-)
+
+Index: qemu-2.4+dfsg/hw/arm/virt-acpi-build.c
+===================================================================
+--- qemu-2.4+dfsg.orig/hw/arm/virt-acpi-build.c
++++ qemu-2.4+dfsg/hw/arm/virt-acpi-build.c
+@@ -431,33 +431,43 @@ build_madt(GArray *table_data, GArray *l
+ 
+     madt = acpi_data_push(table_data, sizeof *madt);
+ 
+-    for (i = 0; i < guest_info->smp_cpus; i++) {
+-        AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data,
+-                                                     sizeof *gicc);
+-        gicc->type = ACPI_APIC_GENERIC_INTERRUPT;
+-        gicc->length = sizeof(*gicc);
+-        gicc->base_address = memmap[VIRT_GIC_CPU].base;
+-        gicc->cpu_interface_number = i;
+-        gicc->arm_mpidr = i;
+-        gicc->uid = i;
+-        if (test_bit(i, cpuinfo->found_cpus)) {
+-            gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
+-        }
+-    }
+-
+     gicd = acpi_data_push(table_data, sizeof *gicd);
+     gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR;
+     gicd->length = sizeof(*gicd);
+     gicd->base_address = memmap[VIRT_GIC_DIST].base;
+ 
+-    gic_msi = acpi_data_push(table_data, sizeof *gic_msi);
+-    gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME;
+-    gic_msi->length = sizeof(*gic_msi);
+-    gic_msi->gic_msi_frame_id = 0;
+-    gic_msi->base_address = cpu_to_le64(memmap[VIRT_GIC_V2M].base);
+-    gic_msi->flags = cpu_to_le32(1);
+-    gic_msi->spi_count = cpu_to_le16(NUM_GICV2M_SPIS);
+-    gic_msi->spi_base = cpu_to_le16(irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE);
++    if (guest_info->gic_version == 3) {
++        AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data,
++                                                         sizeof *gicr);
++
++        gicr->type = ACPI_APIC_GENERIC_REDISTRIBUTOR;
++        gicr->length = sizeof(*gicr);
++        gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base);
++        gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size);
++    } else {
++        for (i = 0; i < guest_info->smp_cpus; i++) {
++            AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data,
++                                                         sizeof *gicc);
++            gicc->type = ACPI_APIC_GENERIC_INTERRUPT;
++            gicc->length = sizeof(*gicc);
++            gicc->base_address = memmap[VIRT_GIC_CPU].base;
++            gicc->cpu_interface_number = i;
++            gicc->arm_mpidr = i;
++            gicc->uid = i;
++            if (test_bit(i, cpuinfo->found_cpus)) {
++                gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
++            }
++        }
++
++        gic_msi = acpi_data_push(table_data, sizeof *gic_msi);
++        gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME;
++        gic_msi->length = sizeof(*gic_msi);
++        gic_msi->gic_msi_frame_id = 0;
++        gic_msi->base_address = cpu_to_le64(memmap[VIRT_GIC_V2M].base);
++        gic_msi->flags = cpu_to_le32(1);
++        gic_msi->spi_count = cpu_to_le16(NUM_GICV2M_SPIS);
++        gic_msi->spi_base = cpu_to_le16(irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE);
++    }
+ 
+     build_header(linker, table_data,
+                  (void *)(table_data->data + madt_start), "APIC",
+Index: qemu-2.4+dfsg/hw/arm/virt.c
+===================================================================
+--- qemu-2.4+dfsg.orig/hw/arm/virt.c
++++ qemu-2.4+dfsg/hw/arm/virt.c
+@@ -49,6 +49,7 @@
+ #include "hw/platform-bus.h"
+ #include "hw/arm/fdt.h"
+ #include "kvm_arm.h"
++#include "qapi/visitor.h"
+ 
+ /* Number of external interrupt lines to configure the GIC with */
+ #define NUM_IRQS 256
+@@ -78,6 +79,7 @@ typedef struct {
+ typedef struct {
+     MachineState parent;
+     bool secure;
++    int32_t gic_version;
+ } VirtMachineState;
+ 
+ #define TYPE_VIRT_MACHINE   "virt"
+@@ -108,6 +110,10 @@ static const MemMapEntry a15memmap[] = {
+     [VIRT_GIC_DIST] =           { 0x08000000, 0x00010000 },
+     [VIRT_GIC_CPU] =            { 0x08010000, 0x00010000 },
+     [VIRT_GIC_V2M] =            { 0x08020000, 0x00001000 },
++    /* The space in between here is reserved for GICv3 CPU/vCPU/HYP */
++    [VIRT_GIC_ITS] =            { 0x08080000, 0x00020000 },
++    /* This redistributor space allows up to 2*64kB*123 CPUs */
++    [VIRT_GIC_REDIST] =         { 0x080A0000, 0x00F60000 },
+     [VIRT_UART] =               { 0x09000000, 0x00001000 },
+     [VIRT_RTC] =                { 0x09010000, 0x00001000 },
+     [VIRT_FW_CFG] =             { 0x09020000, 0x0000000a },
+@@ -250,7 +256,7 @@ static void fdt_add_psci_node(const Virt
+     qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn);
+ }
+ 
+-static void fdt_add_timer_nodes(const VirtBoardInfo *vbi)
++static void fdt_add_timer_nodes(const VirtBoardInfo *vbi, int gictype)
+ {
+     /* Note that on A15 h/w these interrupts are level-triggered,
+      * but for the GIC implementation provided by both QEMU and KVM
+@@ -259,8 +265,11 @@ static void fdt_add_timer_nodes(const Vi
+     ARMCPU *armcpu;
+     uint32_t irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI;
+ 
+-    irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START,
+-                         GIC_FDT_IRQ_PPI_CPU_WIDTH, (1 << vbi->smp_cpus) - 1);
++    if (gictype == 2) {
++        irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START,
++                             GIC_FDT_IRQ_PPI_CPU_WIDTH,
++                             (1 << vbi->smp_cpus) - 1);
++    }
+ 
+     qemu_fdt_add_subnode(vbi->fdt, "/timer");
+ 
+@@ -320,25 +329,36 @@ static void fdt_add_v2m_gic_node(VirtBoa
+     qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->v2m_phandle);
+ }
+ 
+-static void fdt_add_gic_node(VirtBoardInfo *vbi)
++static void fdt_add_gic_node(VirtBoardInfo *vbi, int type)
+ {
+     vbi->gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
+     qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", vbi->gic_phandle);
+ 
+     qemu_fdt_add_subnode(vbi->fdt, "/intc");
+-    /* 'cortex-a15-gic' means 'GIC v2' */
+-    qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible",
+-                            "arm,cortex-a15-gic");
+     qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3);
+     qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0);
+-    qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg",
+-                                     2, vbi->memmap[VIRT_GIC_DIST].base,
+-                                     2, vbi->memmap[VIRT_GIC_DIST].size,
+-                                     2, vbi->memmap[VIRT_GIC_CPU].base,
+-                                     2, vbi->memmap[VIRT_GIC_CPU].size);
+     qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#address-cells", 0x2);
+     qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#size-cells", 0x2);
+     qemu_fdt_setprop(vbi->fdt, "/intc", "ranges", NULL, 0);
++    if (type == 3) {
++        qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible",
++                                "arm,gic-v3");
++        qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg",
++                                     2, vbi->memmap[VIRT_GIC_DIST].base,
++                                     2, vbi->memmap[VIRT_GIC_DIST].size,
++                                     2, vbi->memmap[VIRT_GIC_REDIST].base,
++                                     2, vbi->memmap[VIRT_GIC_REDIST].size);
++    } else {
++        /* 'cortex-a15-gic' means 'GIC v2' */
++        qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible",
++                                "arm,cortex-a15-gic");
++        qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg",
++                                      2, vbi->memmap[VIRT_GIC_DIST].base,
++                                      2, vbi->memmap[VIRT_GIC_DIST].size,
++                                      2, vbi->memmap[VIRT_GIC_CPU].base,
++                                      2, vbi->memmap[VIRT_GIC_CPU].size);
++    }
++
+     qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", vbi->gic_phandle);
+ }
+ 
+@@ -361,18 +381,18 @@ static void create_v2m(VirtBoardInfo *vb
+     fdt_add_v2m_gic_node(vbi);
+ }
+ 
+-static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
++static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type)
+ {
+-    /* We create a standalone GIC v2 */
++    /* We create a standalone GIC */
+     DeviceState *gicdev;
+     SysBusDevice *gicbusdev;
+     const char *gictype;
+     int i;
+ 
+-    gictype = gic_class_name();
++    gictype = (type == 3) ? gicv3_class_name() : gic_class_name();
+ 
+     gicdev = qdev_create(NULL, gictype);
+-    qdev_prop_set_uint32(gicdev, "revision", 2);
++    qdev_prop_set_uint32(gicdev, "revision", type);
+     qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
+     /* Note that the num-irq property counts both internal and external
+      * interrupts; there are always 32 of the former (mandated by GIC spec).
+@@ -381,7 +401,11 @@ static void create_gic(VirtBoardInfo *vb
+     qdev_init_nofail(gicdev);
+     gicbusdev = SYS_BUS_DEVICE(gicdev);
+     sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base);
+-    sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base);
++    if (type == 3) {
++        sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_REDIST].base);
++    } else {
++        sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base);
++    }
+ 
+     /* Wire the outputs from each CPU's generic timer to the
+      * appropriate GIC PPI inputs, and the GIC's IRQ output to
+@@ -408,9 +432,11 @@ static void create_gic(VirtBoardInfo *vb
+         pic[i] = qdev_get_gpio_in(gicdev, i);
+     }
+ 
+-    fdt_add_gic_node(vbi);
++    fdt_add_gic_node(vbi, type);
+ 
+-    create_v2m(vbi, pic);
++    if (type == 2) {
++        create_v2m(vbi, pic);
++    }
+ }
+ 
+ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
+@@ -714,7 +740,10 @@ static void create_pcie(const VirtBoardI
+     qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0,
+                            nr_pcie_buses - 1);
+ 
+-    qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", vbi->v2m_phandle);
++    if (vbi->v2m_phandle) {
++        qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent",
++                               vbi->v2m_phandle);
++    }
+ 
+     qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
+                                  2, base_ecam, 2, size_ecam);
+@@ -792,6 +821,7 @@ static void machvirt_init(MachineState *
+     VirtMachineState *vms = VIRT_MACHINE(machine);
+     qemu_irq pic[NUM_IRQS];
+     MemoryRegion *sysmem = get_system_memory();
++    int gic_version = vms->gic_version;
+     int n;
+     MemoryRegion *ram = g_new(MemoryRegion, 1);
+     const char *cpu_model = machine->cpu_model;
+@@ -804,6 +834,18 @@ static void machvirt_init(MachineState *
+         cpu_model = "cortex-a15";
+     }
+ 
++    /* We can probe only here because during property set
++     * KVM is not available yet
++     */
++    if (!gic_version) {
++        gic_version = kvm_arm_vgic_probe();
++        if (!gic_version) {
++            error_report("Unable to determine GIC version supported by host\n"
++                         "Probably KVM acceleration is not supported\n");
++            exit(1);
++        }
++    }
++
+     /* Separate the actual CPU model name from any appended features */
+     cpustr = g_strsplit(cpu_model, ",", 2);
+ 
+@@ -864,7 +906,7 @@ static void machvirt_init(MachineState *
+         object_property_set_bool(cpuobj, true, "realized", NULL);
+     }
+     g_strfreev(cpustr);
+-    fdt_add_timer_nodes(vbi);
++    fdt_add_timer_nodes(vbi, gic_version);
+     fdt_add_cpu_nodes(vbi);
+     fdt_add_psci_node(vbi);
+ 
+@@ -874,7 +916,7 @@ static void machvirt_init(MachineState *
+ 
+     create_flash(vbi);
+ 
+-    create_gic(vbi, pic);
++    create_gic(vbi, pic, gic_version);
+ 
+     create_uart(vbi, pic);
+ 
+@@ -895,6 +937,7 @@ static void machvirt_init(MachineState *
+     guest_info->fw_cfg = fw_cfg_find();
+     guest_info->memmap = vbi->memmap;
+     guest_info->irqmap = vbi->irqmap;
++    guest_info->gic_version = gic_version;
+     guest_info_state->machine_done.notify = virt_guest_info_machine_done;
+     qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
+ 
+@@ -932,6 +975,31 @@ static void virt_set_secure(Object *obj,
+     vms->secure = value;
+ }
+ 
++static char *virt_get_gic_version(Object *obj, Error **errp)
++{
++    VirtMachineState *vms = VIRT_MACHINE(obj);
++    const char *val = vms->gic_version == 3 ? "3" : "2";
++
++    return g_strdup(val);
++}
++
++static void virt_set_gic_version(Object *obj, const char *value, Error **errp)
++{
++    VirtMachineState *vms = VIRT_MACHINE(obj);
++
++    if (!strcmp(value, "3")) {
++        vms->gic_version = 3;
++    } else if (!strcmp(value, "2")) {
++        vms->gic_version = 2;
++    } else if (!strcmp(value, "host")) {
++        vms->gic_version = 0; /* Will probe later */
++    } else {
++        error_report("Invalid gic-version option value\n"
++                     "Allowed values are: 3, 2, host\n");
++        exit(1);
++    }
++}
++
+ static void virt_instance_init(Object *obj)
+ {
+     VirtMachineState *vms = VIRT_MACHINE(obj);
+@@ -944,6 +1012,13 @@ static void virt_instance_init(Object *o
+                                     "Set on/off to enable/disable the ARM "
+                                     "Security Extensions (TrustZone)",
+                                     NULL);
++    /* Default GIC type is v2 */
++    vms->gic_version = 2;
++    object_property_add_str(obj, "gic-version", virt_get_gic_version,
++                        virt_set_gic_version, NULL);
++    object_property_set_description(obj, "gic-version",
++                                    "Set GIC version. "
++                                    "Valid values are 2, 3 and host", NULL);
+ }
+ 
+ static void virt_class_init(ObjectClass *oc, void *data)
+@@ -953,7 +1028,10 @@ static void virt_class_init(ObjectClass
+     mc->name = TYPE_VIRT_MACHINE;
+     mc->desc = "ARM Virtual Machine",
+     mc->init = machvirt_init;
+-    mc->max_cpus = 8;
++    /* Our maximum number of CPUs depends on how many redistributors
++     * we can fit into memory map
++     */
++    mc->max_cpus = a15memmap[VIRT_GIC_REDIST].size / 0x20000;
+     mc->has_dynamic_sysbus = true;
+     mc->block_default_type = IF_VIRTIO;
+     mc->no_cdrom = 1;
+Index: qemu-2.4+dfsg/include/hw/acpi/acpi-defs.h
+===================================================================
+--- qemu-2.4+dfsg.orig/include/hw/acpi/acpi-defs.h
++++ qemu-2.4+dfsg/include/hw/acpi/acpi-defs.h
+@@ -384,6 +384,15 @@ struct AcpiMadtGenericMsiFrame {
+ 
+ typedef struct AcpiMadtGenericMsiFrame AcpiMadtGenericMsiFrame;
+ 
++struct AcpiMadtGenericRedistributor {
++    ACPI_SUB_HEADER_DEF
++    uint16_t reserved;
++    uint64_t base_address;
++    uint32_t range_length;
++} QEMU_PACKED;
++
++typedef struct AcpiMadtGenericRedistributor AcpiMadtGenericRedistributor;
++
+ /*
+  * Generic Timer Description Table (GTDT)
+  */
+Index: qemu-2.4+dfsg/include/hw/arm/virt-acpi-build.h
+===================================================================
+--- qemu-2.4+dfsg.orig/include/hw/arm/virt-acpi-build.h
++++ qemu-2.4+dfsg/include/hw/arm/virt-acpi-build.h
+@@ -31,6 +31,7 @@ typedef struct VirtGuestInfo {
+     FWCfgState *fw_cfg;
+     const MemMapEntry *memmap;
+     const int *irqmap;
++    int gic_version;
+ } VirtGuestInfo;
+ 
+ 
+Index: qemu-2.4+dfsg/include/hw/arm/virt.h
+===================================================================
+--- qemu-2.4+dfsg.orig/include/hw/arm/virt.h
++++ qemu-2.4+dfsg/include/hw/arm/virt.h
+@@ -46,6 +46,9 @@ enum {
+     VIRT_CPUPERIPHS,
+     VIRT_GIC_DIST,
+     VIRT_GIC_CPU,
++    VIRT_GIC_V2M,
++    VIRT_GIC_ITS,
++    VIRT_GIC_REDIST,
+     VIRT_UART,
+     VIRT_MMIO,
+     VIRT_RTC,
+@@ -54,7 +57,6 @@ enum {
+     VIRT_PCIE_MMIO,
+     VIRT_PCIE_PIO,
+     VIRT_PCIE_ECAM,
+-    VIRT_GIC_V2M,
+     VIRT_PLATFORM_BUS,
+ };
+ 
diff -Nru qemu-2.4+dfsg/debian/patches/hw-intc-Implement-GIC-500-base-class.patch qemu-2.4+dfsg/debian/patches/hw-intc-Implement-GIC-500-base-class.patch
--- qemu-2.4+dfsg/debian/patches/hw-intc-Implement-GIC-500-base-class.patch	1969-12-31 17:00:00.000000000 -0700
+++ qemu-2.4+dfsg/debian/patches/hw-intc-Implement-GIC-500-base-class.patch	2015-10-06 16:42:41.000000000 -0600
@@ -0,0 +1,263 @@
+From ff8f06ee7680fb505079d33caaf8f5ebff0853bc Mon Sep 17 00:00:00 2001
+From: Shlomo Pongratz <shlomo.pongr...@huawei.com>
+Date: Thu, 24 Sep 2015 01:29:36 +0100
+Subject: [PATCH 23/27] hw/intc: Implement GIC-500 base class
+
+This class is to be used by both software and KVM implementations of GICv3
+
+Currently it is mostly a placeholder, but in future it is supposed to hold
+qemu's representation of GICv3 state, which is necessary for migration.
+
+The interface of this class is fully compatible with GICv2 one. This is
+done in order to simplify integration with existing code.
+
+Signed-off-by: Shlomo Pongratz <shlomo.pongr...@huawei.com>
+Signed-off-by: Pavel Fedin <p.fe...@samsung.com>
+Reviewed-by: Eric Auger <eric.au...@linaro.org>
+Tested-by: Ashok kumar <ash...@broadcom.com>
+Reviewed-by: Peter Maydell <peter.mayd...@linaro.org>
+Message-id: aff8baaee493cdcab0694b4a1d4dd5ff27c37ed2.1441784344.git.p.fe...@samsung.com
+Signed-off-by: Peter Maydell <peter.mayd...@linaro.org>
+---
+ hw/intc/Makefile.objs              |   1 +
+ hw/intc/arm_gicv3_common.c         | 140 +++++++++++++++++++++++++++++++++++++
+ include/hw/intc/arm_gicv3_common.h |  68 ++++++++++++++++++
+ 3 files changed, 209 insertions(+)
+ create mode 100644 hw/intc/arm_gicv3_common.c
+ create mode 100644 include/hw/intc/arm_gicv3_common.h
+
+diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
+index 092d8a8..1317e5a 100644
+--- a/hw/intc/Makefile.objs
++++ b/hw/intc/Makefile.objs
+@@ -12,6 +12,7 @@ common-obj-$(CONFIG_IOAPIC) += ioapic_common.o
+ common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o
+ common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
+ common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
++common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
+ common-obj-$(CONFIG_OPENPIC) += openpic.o
+ 
+ obj-$(CONFIG_APIC) += apic.o apic_common.o
+diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
+new file mode 100644
+index 0000000..032ece2
+--- /dev/null
++++ b/hw/intc/arm_gicv3_common.c
+@@ -0,0 +1,140 @@
++/*
++ * ARM GICv3 support - common bits of emulated and KVM kernel model
++ *
++ * Copyright (c) 2012 Linaro Limited
++ * Copyright (c) 2015 Huawei.
++ * Written by Peter Maydell
++ * Extended to 64 cores by Shlomo Pongratz
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "hw/intc/arm_gicv3_common.h"
++
++static void gicv3_pre_save(void *opaque)
++{
++    GICv3State *s = (GICv3State *)opaque;
++    ARMGICv3CommonClass *c = ARM_GICV3_COMMON_GET_CLASS(s);
++
++    if (c->pre_save) {
++        c->pre_save(s);
++    }
++}
++
++static int gicv3_post_load(void *opaque, int version_id)
++{
++    GICv3State *s = (GICv3State *)opaque;
++    ARMGICv3CommonClass *c = ARM_GICV3_COMMON_GET_CLASS(s);
++
++    if (c->post_load) {
++        c->post_load(s);
++    }
++    return 0;
++}
++
++static const VMStateDescription vmstate_gicv3 = {
++    .name = "arm_gicv3",
++    .unmigratable = 1,
++    .pre_save = gicv3_pre_save,
++    .post_load = gicv3_post_load,
++};
++
++void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
++                              const MemoryRegionOps *ops)
++{
++    SysBusDevice *sbd = SYS_BUS_DEVICE(s);
++    int i;
++
++    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
++     * GPIO array layout is thus:
++     *  [0..N-1] spi
++     *  [N..N+31] PPIs for CPU 0
++     *  [N+32..N+63] PPIs for CPU 1
++     *   ...
++     */
++    i = s->num_irq - GIC_INTERNAL + GIC_INTERNAL * s->num_cpu;
++    qdev_init_gpio_in(DEVICE(s), handler, i);
++
++    s->parent_irq = g_malloc(s->num_cpu * sizeof(qemu_irq));
++    s->parent_fiq = g_malloc(s->num_cpu * sizeof(qemu_irq));
++
++    for (i = 0; i < s->num_cpu; i++) {
++        sysbus_init_irq(sbd, &s->parent_irq[i]);
++    }
++    for (i = 0; i < s->num_cpu; i++) {
++        sysbus_init_irq(sbd, &s->parent_fiq[i]);
++    }
++
++    memory_region_init_io(&s->iomem_dist, OBJECT(s), ops, s,
++                          "gicv3_dist", 0x10000);
++    memory_region_init_io(&s->iomem_redist, OBJECT(s), ops ? &ops[1] : NULL, s,
++                          "gicv3_redist", 0x20000 * s->num_cpu);
++
++    sysbus_init_mmio(sbd, &s->iomem_dist);
++    sysbus_init_mmio(sbd, &s->iomem_redist);
++}
++
++static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
++{
++    GICv3State *s = ARM_GICV3_COMMON(dev);
++
++    /* revision property is actually reserved and currently used only in order
++     * to keep the interface compatible with GICv2 code, avoiding extra
++     * conditions. However, in future it could be used, for example, if we
++     * implement GICv4.
++     */
++    if (s->revision != 3) {
++        error_setg(errp, "unsupported GIC revision %d", s->revision);
++        return;
++    }
++}
++
++static void arm_gicv3_common_reset(DeviceState *dev)
++{
++    /* TODO */
++}
++
++static Property arm_gicv3_common_properties[] = {
++    DEFINE_PROP_UINT32("num-cpu", GICv3State, num_cpu, 1),
++    DEFINE_PROP_UINT32("num-irq", GICv3State, num_irq, 32),
++    DEFINE_PROP_UINT32("revision", GICv3State, revision, 3),
++    DEFINE_PROP_BOOL("has-security-extensions", GICv3State, security_extn, 0),
++    DEFINE_PROP_END_OF_LIST(),
++};
++
++static void arm_gicv3_common_class_init(ObjectClass *klass, void *data)
++{
++    DeviceClass *dc = DEVICE_CLASS(klass);
++
++    dc->reset = arm_gicv3_common_reset;
++    dc->realize = arm_gicv3_common_realize;
++    dc->props = arm_gicv3_common_properties;
++    dc->vmsd = &vmstate_gicv3;
++}
++
++static const TypeInfo arm_gicv3_common_type = {
++    .name = TYPE_ARM_GICV3_COMMON,
++    .parent = TYPE_SYS_BUS_DEVICE,
++    .instance_size = sizeof(GICv3State),
++    .class_size = sizeof(ARMGICv3CommonClass),
++    .class_init = arm_gicv3_common_class_init,
++    .abstract = true,
++};
++
++static void register_types(void)
++{
++    type_register_static(&arm_gicv3_common_type);
++}
++
++type_init(register_types)
+diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
+new file mode 100644
+index 0000000..c2fd8da
+--- /dev/null
++++ b/include/hw/intc/arm_gicv3_common.h
+@@ -0,0 +1,68 @@
++/*
++ * ARM GIC support
++ *
++ * Copyright (c) 2012 Linaro Limited
++ * Copyright (c) 2015 Huawei.
++ * Written by Peter Maydell
++ * Extended to 64 cores by Shlomo Pongratz
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef HW_ARM_GICV3_COMMON_H
++#define HW_ARM_GICV3_COMMON_H
++
++#include "hw/sysbus.h"
++#include "hw/intc/arm_gic_common.h"
++
++typedef struct GICv3State {
++    /*< private >*/
++    SysBusDevice parent_obj;
++    /*< public >*/
++
++    qemu_irq *parent_irq;
++    qemu_irq *parent_fiq;
++
++    MemoryRegion iomem_dist; /* Distributor */
++    MemoryRegion iomem_redist; /* Redistributors */
++
++    uint32_t num_cpu;
++    uint32_t num_irq;
++    uint32_t revision;
++    bool security_extn;
++
++    int dev_fd; /* kvm device fd if backed by kvm vgic support */
++} GICv3State;
++
++#define TYPE_ARM_GICV3_COMMON "arm-gicv3-common"
++#define ARM_GICV3_COMMON(obj) \
++     OBJECT_CHECK(GICv3State, (obj), TYPE_ARM_GICV3_COMMON)
++#define ARM_GICV3_COMMON_CLASS(klass) \
++     OBJECT_CLASS_CHECK(ARMGICv3CommonClass, (klass), TYPE_ARM_GICV3_COMMON)
++#define ARM_GICV3_COMMON_GET_CLASS(obj) \
++     OBJECT_GET_CLASS(ARMGICv3CommonClass, (obj), TYPE_ARM_GICV3_COMMON)
++
++typedef struct ARMGICv3CommonClass {
++    /*< private >*/
++    SysBusDeviceClass parent_class;
++    /*< public >*/
++
++    void (*pre_save)(GICv3State *s);
++    void (*post_load)(GICv3State *s);
++} ARMGICv3CommonClass;
++
++void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
++                              const MemoryRegionOps *ops);
++
++#endif
+-- 
+2.6.0
+
diff -Nru qemu-2.4+dfsg/debian/patches/hw-intc-Initial-implementation-of-vGICv3.patch qemu-2.4+dfsg/debian/patches/hw-intc-Initial-implementation-of-vGICv3.patch
--- qemu-2.4+dfsg/debian/patches/hw-intc-Initial-implementation-of-vGICv3.patch	1969-12-31 17:00:00.000000000 -0700
+++ qemu-2.4+dfsg/debian/patches/hw-intc-Initial-implementation-of-vGICv3.patch	2015-10-06 16:42:41.000000000 -0600
@@ -0,0 +1,246 @@
+From a7bf30342e6a7924132a5c70047928261d3c7e42 Mon Sep 17 00:00:00 2001
+From: Pavel Fedin <p.fe...@samsung.com>
+Date: Thu, 24 Sep 2015 01:29:37 +0100
+Subject: [PATCH 26/27] hw/intc: Initial implementation of vGICv3
+
+This is the initial version of KVM-accelerated GICv3 support.
+State load and save are not yet supported, live migration is
+not possible.
+
+In order to get correct class name in a simpler way, gicv3_class_name()
+function is implemented, similar to gic_class_name().
+
+Signed-off-by: Pavel Fedin <p.fe...@samsung.com>
+Reviewed-by: Peter Maydell <peter.mayd...@linaro.org>
+Tested-by: Ashok kumar <ash...@broadcom.com>
+Message-id: 69d8f01d14994d7a1a140e96aef59fd332d02293.1441784344.git.p.fe...@samsung.com
+Signed-off-by: Peter Maydell <peter.mayd...@linaro.org>
+---
+ hw/intc/Makefile.objs   |   1 +
+ hw/intc/arm_gicv3_kvm.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++
+ target-arm/kvm_arm.h    |  10 ++++
+ target-arm/machine.c    |  18 ++++++
+ 4 files changed, 178 insertions(+)
+ create mode 100644 hw/intc/arm_gicv3_kvm.c
+
+diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
+index 1317e5a..004b0c2 100644
+--- a/hw/intc/Makefile.objs
++++ b/hw/intc/Makefile.objs
+@@ -17,6 +17,7 @@ common-obj-$(CONFIG_OPENPIC) += openpic.o
+ 
+ obj-$(CONFIG_APIC) += apic.o apic_common.o
+ obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
++obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_kvm.o
+ obj-$(CONFIG_STELLARIS) += armv7m_nvic.o
+ obj-$(CONFIG_EXYNOS4) += exynos4210_gic.o exynos4210_combiner.o
+ obj-$(CONFIG_GRLIB) += grlib_irqmp.o
+diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
+new file mode 100644
+index 0000000..b48f78f
+--- /dev/null
++++ b/hw/intc/arm_gicv3_kvm.c
+@@ -0,0 +1,149 @@
++/*
++ * ARM Generic Interrupt Controller using KVM in-kernel support
++ *
++ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
++ * Written by Pavel Fedin
++ * Based on vGICv2 code by Peter Maydell
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "hw/intc/arm_gicv3_common.h"
++#include "hw/sysbus.h"
++#include "sysemu/kvm.h"
++#include "kvm_arm.h"
++#include "vgic_common.h"
++
++#ifdef DEBUG_GICV3_KVM
++#define DPRINTF(fmt, ...) \
++    do { fprintf(stderr, "kvm_gicv3: " fmt, ## __VA_ARGS__); } while (0)
++#else
++#define DPRINTF(fmt, ...) \
++    do { } while (0)
++#endif
++
++#define TYPE_KVM_ARM_GICV3 "kvm-arm-gicv3"
++#define KVM_ARM_GICV3(obj) \
++     OBJECT_CHECK(GICv3State, (obj), TYPE_KVM_ARM_GICV3)
++#define KVM_ARM_GICV3_CLASS(klass) \
++     OBJECT_CLASS_CHECK(KVMARMGICv3Class, (klass), TYPE_KVM_ARM_GICV3)
++#define KVM_ARM_GICV3_GET_CLASS(obj) \
++     OBJECT_GET_CLASS(KVMARMGICv3Class, (obj), TYPE_KVM_ARM_GICV3)
++
++typedef struct KVMARMGICv3Class {
++    ARMGICv3CommonClass parent_class;
++    DeviceRealize parent_realize;
++    void (*parent_reset)(DeviceState *dev);
++} KVMARMGICv3Class;
++
++static void kvm_arm_gicv3_set_irq(void *opaque, int irq, int level)
++{
++    GICv3State *s = (GICv3State *)opaque;
++
++    kvm_arm_gic_set_irq(s->num_irq, irq, level);
++}
++
++static void kvm_arm_gicv3_put(GICv3State *s)
++{
++    /* TODO */
++    DPRINTF("Cannot put kernel gic state, no kernel interface\n");
++}
++
++static void kvm_arm_gicv3_get(GICv3State *s)
++{
++    /* TODO */
++    DPRINTF("Cannot get kernel gic state, no kernel interface\n");
++}
++
++static void kvm_arm_gicv3_reset(DeviceState *dev)
++{
++    GICv3State *s = ARM_GICV3_COMMON(dev);
++    KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s);
++
++    DPRINTF("Reset\n");
++
++    kgc->parent_reset(dev);
++    kvm_arm_gicv3_put(s);
++}
++
++static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
++{
++    GICv3State *s = KVM_ARM_GICV3(dev);
++    KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s);
++    Error *local_err = NULL;
++
++    DPRINTF("kvm_arm_gicv3_realize\n");
++
++    kgc->parent_realize(dev, &local_err);
++    if (local_err) {
++        error_propagate(errp, local_err);
++        return;
++    }
++
++    if (s->security_extn) {
++        error_setg(errp, "the in-kernel VGICv3 does not implement the "
++                   "security extensions");
++        return;
++    }
++
++    gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL);
++
++    /* Try to create the device via the device control API */
++    s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V3, false);
++    if (s->dev_fd < 0) {
++        error_setg_errno(errp, -s->dev_fd, "error creating in-kernel VGIC");
++        return;
++    }
++
++    kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
++                      0, &s->num_irq, true);
++
++    /* Tell the kernel to complete VGIC initialization now */
++    kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
++                      KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true);
++
++    kvm_arm_register_device(&s->iomem_dist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
++                            KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd);
++    kvm_arm_register_device(&s->iomem_redist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
++                            KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd);
++}
++
++static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data)
++{
++    DeviceClass *dc = DEVICE_CLASS(klass);
++    ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass);
++    KVMARMGICv3Class *kgc = KVM_ARM_GICV3_CLASS(klass);
++
++    agcc->pre_save = kvm_arm_gicv3_get;
++    agcc->post_load = kvm_arm_gicv3_put;
++    kgc->parent_realize = dc->realize;
++    kgc->parent_reset = dc->reset;
++    dc->realize = kvm_arm_gicv3_realize;
++    dc->reset = kvm_arm_gicv3_reset;
++}
++
++static const TypeInfo kvm_arm_gicv3_info = {
++    .name = TYPE_KVM_ARM_GICV3,
++    .parent = TYPE_ARM_GICV3_COMMON,
++    .instance_size = sizeof(GICv3State),
++    .class_init = kvm_arm_gicv3_class_init,
++    .class_size = sizeof(KVMARMGICv3Class),
++};
++
++static void kvm_arm_gicv3_register_types(void)
++{
++    type_register_static(&kvm_arm_gicv3_info);
++}
++
++type_init(kvm_arm_gicv3_register_types)
+diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h
+index 10ce771..b516041 100644
+--- a/target-arm/kvm_arm.h
++++ b/target-arm/kvm_arm.h
+@@ -205,4 +205,14 @@ static inline const char *gic_class_name(void)
+     return kvm_irqchip_in_kernel() ? "kvm-arm-gic" : "arm_gic";
+ }
+ 
++/**
++ * gicv3_class_name
++ *
++ * Return name of GICv3 class to use depending on whether KVM acceleration is
++ * in use. May throw an error if the chosen implementation is not available.
++ *
++ * Returns: class name to use
++ */
++const char *gicv3_class_name(void);
++
+ #endif
+diff --git a/target-arm/machine.c b/target-arm/machine.c
+index 32adfe7..36a0d15 100644
+--- a/target-arm/machine.c
++++ b/target-arm/machine.c
+@@ -1,5 +1,6 @@
+ #include "hw/hw.h"
+ #include "hw/boards.h"
++#include "qemu/error-report.h"
+ #include "sysemu/kvm.h"
+ #include "kvm_arm.h"
+ #include "internals.h"
+@@ -328,3 +329,20 @@ const VMStateDescription vmstate_arm_cpu = {
+         NULL
+     }
+ };
++
++const char *gicv3_class_name(void)
++{
++    if (kvm_irqchip_in_kernel()) {
++#ifdef TARGET_AARCH64
++        return "kvm-arm-gicv3";
++#else
++        error_report("KVM GICv3 acceleration is not supported on this "
++                     "platform\n");
++#endif
++    } else {
++        /* TODO: Software emulation is not implemented yet */
++        error_report("KVM is currently required for GICv3 emulation\n");
++    }
++
++    exit(1);
++}
+-- 
+2.6.0
+
diff -Nru qemu-2.4+dfsg/debian/patches/intc-gic-Extract-some-reusable-vGIC-code.patch qemu-2.4+dfsg/debian/patches/intc-gic-Extract-some-reusable-vGIC-code.patch
--- qemu-2.4+dfsg/debian/patches/intc-gic-Extract-some-reusable-vGIC-code.patch	1969-12-31 17:00:00.000000000 -0700
+++ qemu-2.4+dfsg/debian/patches/intc-gic-Extract-some-reusable-vGIC-code.patch	2015-10-06 16:42:41.000000000 -0600
@@ -0,0 +1,346 @@
+From 4b3cfe72d9b9c53be31a88e7eebdda14f1757d3e Mon Sep 17 00:00:00 2001
+From: Pavel Fedin <p.fe...@samsung.com>
+Date: Thu, 24 Sep 2015 01:29:36 +0100
+Subject: [PATCH 24/27] intc/gic: Extract some reusable vGIC code
+
+Some functions previously used only by vGICv2 are useful also for vGICv3
+implementation. Untie them from GICState and make accessible from within
+other modules:
+- kvm_arm_gic_set_irq()
+- kvm_gic_supports_attr() - moved to common code and renamed to
+  kvm_device_check_attr()
+- kvm_gic_access() - turned into GIC-independent kvm_device_access().
+  Data pointer changed to void * because some GICv3 registers are
+  64-bit wide
+
+Some of these changes are not used right now, but they will be helpful for
+implementing live migration.
+
+Actually kvm_dist_get() and kvm_dist_put() could also be made reusable, but
+they would require two extra parameters (s->dev_fd and s->num_cpu) as well as
+lots of typecasts of 's' to DeviceState * and back to GICState *. This makes
+the code very ugly so i decided to stop at this point. I tried also an
+approach with making a base class for all possible GICs, but it would contain
+only three variables (dev_fd, cpu_num and irq_num), and accessing them through
+the rest of the code would be again tedious (either ugly casts or qemu-style
+separate object pointer). So i disliked it too.
+
+Signed-off-by: Pavel Fedin <p.fe...@samsung.com>
+Tested-by: Ashok kumar <ash...@broadcom.com>
+Reviewed-by: Peter Maydell <peter.mayd...@linaro.org>
+Message-id: 2ef56d1dd64ffb75ed02a10dcdaf605e5b8ff4f8.1441784344.git.p.fe...@samsung.com
+Signed-off-by: Peter Maydell <peter.mayd...@linaro.org>
+---
+ hw/intc/arm_gic_kvm.c | 98 +++++++++++++++++----------------------------------
+ hw/intc/vgic_common.h | 35 ++++++++++++++++++
+ include/sysemu/kvm.h  | 26 ++++++++++++++
+ kvm-all.c             | 34 ++++++++++++++++++
+ 4 files changed, 128 insertions(+), 65 deletions(-)
+ create mode 100644 hw/intc/vgic_common.h
+
+diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c
+index e5d0f67..e8b2386 100644
+--- a/hw/intc/arm_gic_kvm.c
++++ b/hw/intc/arm_gic_kvm.c
+@@ -23,6 +23,7 @@
+ #include "sysemu/kvm.h"
+ #include "kvm_arm.h"
+ #include "gic_internal.h"
++#include "vgic_common.h"
+ 
+ //#define DEBUG_GIC_KVM
+ 
+@@ -52,7 +53,7 @@ typedef struct KVMARMGICClass {
+     void (*parent_reset)(DeviceState *dev);
+ } KVMARMGICClass;
+ 
+-static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
++void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level)
+ {
+     /* Meaning of the 'irq' parameter:
+      *  [0..N-1] : external interrupts
+@@ -63,10 +64,9 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
+      * has separate fields in the irq number for type,
+      * CPU number and interrupt number.
+      */
+-    GICState *s = (GICState *)opaque;
+     int kvm_irq, irqtype, cpu;
+ 
+-    if (irq < (s->num_irq - GIC_INTERNAL)) {
++    if (irq < (num_irq - GIC_INTERNAL)) {
+         /* External interrupt. The kernel numbers these like the GIC
+          * hardware, with external interrupt IDs starting after the
+          * internal ones.
+@@ -77,7 +77,7 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
+     } else {
+         /* Internal interrupt: decode into (cpu, interrupt id) */
+         irqtype = KVM_ARM_IRQ_TYPE_PPI;
+-        irq -= (s->num_irq - GIC_INTERNAL);
++        irq -= (num_irq - GIC_INTERNAL);
+         cpu = irq / GIC_INTERNAL;
+         irq %= GIC_INTERNAL;
+     }
+@@ -87,69 +87,36 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
+     kvm_set_irq(kvm_state, kvm_irq, !!level);
+ }
+ 
+-static bool kvm_arm_gic_can_save_restore(GICState *s)
+-{
+-    return s->dev_fd >= 0;
+-}
+-
+-static bool kvm_gic_supports_attr(GICState *s, int group, int attrnum)
++static void kvm_arm_gicv2_set_irq(void *opaque, int irq, int level)
+ {
+-    struct kvm_device_attr attr = {
+-        .group = group,
+-        .attr = attrnum,
+-        .flags = 0,
+-    };
+-
+-    if (s->dev_fd == -1) {
+-        return false;
+-    }
++    GICState *s = (GICState *)opaque;
+ 
+-    return kvm_device_ioctl(s->dev_fd, KVM_HAS_DEVICE_ATTR, &attr) == 0;
++    kvm_arm_gic_set_irq(s->num_irq, irq, level);
+ }
+ 
+-static void kvm_gic_access(GICState *s, int group, int offset,
+-                                   int cpu, uint32_t *val, bool write)
++static bool kvm_arm_gic_can_save_restore(GICState *s)
+ {
+-    struct kvm_device_attr attr;
+-    int type;
+-    int err;
+-
+-    cpu = cpu & 0xff;
+-
+-    attr.flags = 0;
+-    attr.group = group;
+-    attr.attr = (((uint64_t)cpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) &
+-                 KVM_DEV_ARM_VGIC_CPUID_MASK) |
+-                (((uint64_t)offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) &
+-                 KVM_DEV_ARM_VGIC_OFFSET_MASK);
+-    attr.addr = (uintptr_t)val;
+-
+-    if (write) {
+-        type = KVM_SET_DEVICE_ATTR;
+-    } else {
+-        type = KVM_GET_DEVICE_ATTR;
+-    }
+-
+-    err = kvm_device_ioctl(s->dev_fd, type, &attr);
+-    if (err < 0) {
+-        fprintf(stderr, "KVM_{SET/GET}_DEVICE_ATTR failed: %s\n",
+-                strerror(-err));
+-        abort();
+-    }
++    return s->dev_fd >= 0;
+ }
+ 
++#define KVM_VGIC_ATTR(offset, cpu) \
++    ((((uint64_t)(cpu) << KVM_DEV_ARM_VGIC_CPUID_SHIFT) & \
++      KVM_DEV_ARM_VGIC_CPUID_MASK) | \
++     (((uint64_t)(offset) << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) & \
++      KVM_DEV_ARM_VGIC_OFFSET_MASK))
++
+ static void kvm_gicd_access(GICState *s, int offset, int cpu,
+                             uint32_t *val, bool write)
+ {
+-    kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
+-                   offset, cpu, val, write);
++    kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
++                      KVM_VGIC_ATTR(offset, cpu), val, write);
+ }
+ 
+ static void kvm_gicc_access(GICState *s, int offset, int cpu,
+                             uint32_t *val, bool write)
+ {
+-    kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
+-                   offset, cpu, val, write);
++    kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
++                      KVM_VGIC_ATTR(offset, cpu), val, write);
+ }
+ 
+ #define for_each_irq_reg(_ctr, _max_irq, _field_width) \
+@@ -559,7 +526,7 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
+         return;
+     }
+ 
+-    gic_init_irqs_and_mmio(s, kvm_arm_gic_set_irq, NULL);
++    gic_init_irqs_and_mmio(s, kvm_arm_gicv2_set_irq, NULL);
+ 
+     for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
+         qemu_irq irq = qdev_get_gpio_in(dev, i);
+@@ -571,23 +538,24 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
+     ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V2, false);
+     if (ret >= 0) {
+         s->dev_fd = ret;
++
++        /* Newstyle API is used, we may have attributes */
++        if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) {
++            uint32_t numirqs = s->num_irq;
++            kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0,
++                              &numirqs, true);
++        }
++        /* Tell the kernel to complete VGIC initialization now */
++        if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
++                                  KVM_DEV_ARM_VGIC_CTRL_INIT)) {
++            kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
++                              KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true);
++        }
+     } else if (ret != -ENODEV && ret != -ENOTSUP) {
+         error_setg_errno(errp, -ret, "error creating in-kernel VGIC");
+         return;
+     }
+ 
+-    if (kvm_gic_supports_attr(s, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) {
+-        uint32_t numirqs = s->num_irq;
+-        kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, 0, &numirqs, 1);
+-    }
+-
+-    /* Tell the kernel to complete VGIC initialization now */
+-    if (kvm_gic_supports_attr(s, KVM_DEV_ARM_VGIC_GRP_CTRL,
+-                              KVM_DEV_ARM_VGIC_CTRL_INIT)) {
+-        kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_CTRL,
+-                          KVM_DEV_ARM_VGIC_CTRL_INIT, 0, 0, 1);
+-    }
+-
+     /* Distributor */
+     kvm_arm_register_device(&s->iomem,
+                             (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
+diff --git a/hw/intc/vgic_common.h b/hw/intc/vgic_common.h
+new file mode 100644
+index 0000000..80d919e
+--- /dev/null
++++ b/hw/intc/vgic_common.h
+@@ -0,0 +1,35 @@
++/*
++ * ARM KVM vGIC utility functions
++ *
++ * Copyright (c) 2015 Samsung Electronics
++ * Written by Pavel Fedin
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef QEMU_ARM_VGIC_COMMON_H
++#define QEMU_ARM_VGIC_COMMON_H
++
++/**
++ * kvm_arm_gic_set_irq - Send an IRQ to the in-kernel vGIC
++ * @num_irq: Total number of IRQs configured for the GIC instance
++ * @irq: qemu internal IRQ line number:
++ *  [0..N-1] : external interrupts
++ *  [N..N+31] : PPI (internal) interrupts for CPU 0
++ *  [N+32..N+63] : PPI (internal interrupts for CPU 1
++ * @level: level of the IRQ line.
++ */
++void kvm_arm_gic_set_irq(uint32_t num_irq, int irq, int level);
++
++#endif
+diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
+index 983e99e..2a58b4d 100644
+--- a/include/sysemu/kvm.h
++++ b/include/sysemu/kvm.h
+@@ -240,6 +240,32 @@ int kvm_device_ioctl(int fd, int type, ...);
+ int kvm_vm_check_attr(KVMState *s, uint32_t group, uint64_t attr);
+ 
+ /**
++ * kvm_device_check_attr - check for existence of a specific device attribute
++ * @fd: The device file descriptor
++ * @group: the group
++ * @attr: the attribute of that group to query for
++ *
++ * Returns: 1 if the attribute exists
++ *          0 if the attribute either does not exist or if the vm device
++ *            interface is unavailable
++ */
++int kvm_device_check_attr(int fd, uint32_t group, uint64_t attr);
++
++/**
++ * kvm_device_access - set or get value of a specific vm attribute
++ * @fd: The device file descriptor
++ * @group: the group
++ * @attr: the attribute of that group to set or get
++ * @val: pointer to a storage area for the value
++ * @write: true for set and false for get operation
++ *
++ * This function is not allowed to fail. Use kvm_device_check_attr()
++ * in order to check for the availability of optional attributes.
++ */
++void kvm_device_access(int fd, int group, uint64_t attr,
++                       void *val, bool write);
++
++/**
+  * kvm_create_device - create a KVM device for the device control API
+  * @KVMState: The KVMState pointer
+  * @type: The KVM device type (see Documentation/virtual/kvm/devices in the
+diff --git a/kvm-all.c b/kvm-all.c
+index de1924c..0be4615 100644
+--- a/kvm-all.c
++++ b/kvm-all.c
+@@ -24,6 +24,7 @@
+ #include "qemu/atomic.h"
+ #include "qemu/option.h"
+ #include "qemu/config-file.h"
++#include "qemu/error-report.h"
+ #include "hw/hw.h"
+ #include "hw/pci/msi.h"
+ #include "hw/s390x/adapter.h"
+@@ -2008,6 +2009,39 @@ int kvm_vm_check_attr(KVMState *s, uint32_t group, uint64_t attr)
+     return ret ? 0 : 1;
+ }
+ 
++int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr)
++{
++    struct kvm_device_attr attribute = {
++        .group = group,
++        .attr = attr,
++        .flags = 0,
++    };
++
++    return kvm_device_ioctl(dev_fd, KVM_HAS_DEVICE_ATTR, &attribute) ? 0 : 1;
++}
++
++void kvm_device_access(int fd, int group, uint64_t attr,
++                       void *val, bool write)
++{
++    struct kvm_device_attr kvmattr;
++    int err;
++
++    kvmattr.flags = 0;
++    kvmattr.group = group;
++    kvmattr.attr = attr;
++    kvmattr.addr = (uintptr_t)val;
++
++    err = kvm_device_ioctl(fd,
++                           write ? KVM_SET_DEVICE_ATTR : KVM_GET_DEVICE_ATTR,
++                           &kvmattr);
++    if (err < 0) {
++        error_report("KVM_%s_DEVICE_ATTR failed: %s\n"
++                     "Group %d attr 0x%016" PRIx64, write ? "SET" : "GET",
++                     strerror(-err), group, attr);
++        abort();
++    }
++}
++
+ int kvm_has_sync_mmu(void)
+ {
+     return kvm_check_extension(kvm_state, KVM_CAP_SYNC_MMU);
+-- 
+2.6.0
+
diff -Nru qemu-2.4+dfsg/debian/patches/Introduce-gic_class_name-instead-of-repeating-condit.patch qemu-2.4+dfsg/debian/patches/Introduce-gic_class_name-instead-of-repeating-condit.patch
--- qemu-2.4+dfsg/debian/patches/Introduce-gic_class_name-instead-of-repeating-condit.patch	1969-12-31 17:00:00.000000000 -0700
+++ qemu-2.4+dfsg/debian/patches/Introduce-gic_class_name-instead-of-repeating-condit.patch	2015-10-06 16:45:56.000000000 -0600
@@ -0,0 +1,89 @@
+From e6fbcbc4e57322a8de1307556e68a4cd6d0d8c8b Mon Sep 17 00:00:00 2001
+From: Pavel Fedin <p.fe...@samsung.com>
+Date: Thu, 13 Aug 2015 11:26:21 +0100
+Subject: [PATCH 3/3] Introduce gic_class_name() instead of repeating condition
+
+This small inline returns correct GIC class name depending on whether we
+use KVM acceleration or not. Avoids duplicating the condition everywhere.
+
+Signed-off-by: Pavel Fedin <p.fe...@samsung.com>
+Reviewed-by: Peter Maydell <peter.mayd...@linaro.org>
+Message-id: 4f26901be9b844b563673ce3ad08eeedbb7a7132.1438758065.git.p.fe...@samsung.com
+Signed-off-by: Peter Maydell <peter.mayd...@linaro.org>
+---
+ hw/arm/virt.c        | 7 +++----
+ hw/cpu/a15mpcore.c   | 8 ++------
+ target-arm/kvm_arm.h | 5 +++++
+ 3 files changed, 10 insertions(+), 10 deletions(-)
+
+Index: qemu-2.4+dfsg/hw/arm/virt.c
+===================================================================
+--- qemu-2.4+dfsg.orig/hw/arm/virt.c
++++ qemu-2.4+dfsg/hw/arm/virt.c
+@@ -48,6 +48,7 @@
+ #include "hw/arm/sysbus-fdt.h"
+ #include "hw/platform-bus.h"
+ #include "hw/arm/fdt.h"
++#include "kvm_arm.h"
+ 
+ /* Number of external interrupt lines to configure the GIC with */
+ #define NUM_IRQS 256
+@@ -365,12 +366,10 @@ static void create_gic(VirtBoardInfo *vb
+     /* We create a standalone GIC v2 */
+     DeviceState *gicdev;
+     SysBusDevice *gicbusdev;
+-    const char *gictype = "arm_gic";
++    const char *gictype;
+     int i;
+ 
+-    if (kvm_irqchip_in_kernel()) {
+-        gictype = "kvm-arm-gic";
+-    }
++    gictype = gic_class_name();
+ 
+     gicdev = qdev_create(NULL, gictype);
+     qdev_prop_set_uint32(gicdev, "revision", 2);
+Index: qemu-2.4+dfsg/hw/cpu/a15mpcore.c
+===================================================================
+--- qemu-2.4+dfsg.orig/hw/cpu/a15mpcore.c
++++ qemu-2.4+dfsg/hw/cpu/a15mpcore.c
+@@ -20,6 +20,7 @@
+ 
+ #include "hw/cpu/a15mpcore.h"
+ #include "sysemu/kvm.h"
++#include "kvm_arm.h"
+ 
+ static void a15mp_priv_set_irq(void *opaque, int irq, int level)
+ {
+@@ -33,16 +34,11 @@ static void a15mp_priv_initfn(Object *ob
+     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+     A15MPPrivState *s = A15MPCORE_PRIV(obj);
+     DeviceState *gicdev;
+-    const char *gictype = "arm_gic";
+-
+-    if (kvm_irqchip_in_kernel()) {
+-        gictype = "kvm-arm-gic";
+-    }
+ 
+     memory_region_init(&s->container, obj, "a15mp-priv-container", 0x8000);
+     sysbus_init_mmio(sbd, &s->container);
+ 
+-    object_initialize(&s->gic, sizeof(s->gic), gictype);
++    object_initialize(&s->gic, sizeof(s->gic), gic_class_name());
+     gicdev = DEVICE(&s->gic);
+     qdev_set_parent_bus(gicdev, sysbus_get_default());
+     qdev_prop_set_uint32(gicdev, "revision", 2);
+Index: qemu-2.4+dfsg/target-arm/kvm_arm.h
+===================================================================
+--- qemu-2.4+dfsg.orig/target-arm/kvm_arm.h
++++ qemu-2.4+dfsg/target-arm/kvm_arm.h
+@@ -191,4 +191,9 @@ int kvm_arm_sync_mpstate_to_qemu(ARMCPU
+ 
+ #endif
+ 
++static inline const char *gic_class_name(void)
++{
++    return kvm_irqchip_in_kernel() ? "kvm-arm-gic" : "arm_gic";
++}
++
+ #endif
diff -Nru qemu-2.4+dfsg/debian/patches/Merge-memory_region_init_reservation-into-memory_reg.patch qemu-2.4+dfsg/debian/patches/Merge-memory_region_init_reservation-into-memory_reg.patch
--- qemu-2.4+dfsg/debian/patches/Merge-memory_region_init_reservation-into-memory_reg.patch	1969-12-31 17:00:00.000000000 -0700
+++ qemu-2.4+dfsg/debian/patches/Merge-memory_region_init_reservation-into-memory_reg.patch	2015-10-06 16:45:07.000000000 -0600
@@ -0,0 +1,86 @@
+From 6d6d2abf2c2e52c0f404d0a31a963e945b0cc7ad Mon Sep 17 00:00:00 2001
+From: Pavel Fedin <p.fe...@samsung.com>
+Date: Thu, 13 Aug 2015 11:26:21 +0100
+Subject: [PATCH 1/3] Merge memory_region_init_reservation() into
+ memory_region_init_io()
+
+Just specifying ops = NULL in some cases can be more convenient than having
+two functions.
+
+Signed-off-by: Pavel Fedin <p.fe...@samsung.com>
+Acked-by: Paolo Bonzini <pbonz...@redhat.com>
+Reviewed-by: Peter Maydell <peter.mayd...@linaro.org>
+Message-id: 78a379ab1b6b30ab497db7971ad336dad1dbee76.1438758065.git.p.fe...@samsung.com
+Signed-off-by: Peter Maydell <peter.mayd...@linaro.org>
+---
+ include/exec/memory.h | 14 +++++++++++---
+ memory.c              | 10 +---------
+ 2 files changed, 12 insertions(+), 12 deletions(-)
+
+Index: qemu-2.4+dfsg/include/exec/memory.h
+===================================================================
+--- qemu-2.4+dfsg.orig/include/exec/memory.h
++++ qemu-2.4+dfsg/include/exec/memory.h
+@@ -437,6 +437,9 @@ void memory_region_init_alias(MemoryRegi
+  * memory_region_init_rom_device:  Initialize a ROM memory region.  Writes are
+  *                                 handled via callbacks.
+  *
++ * If NULL callbacks pointer is given, then I/O space is not supposed to be
++ * handled by QEMU itself. Any access via the memory API will cause an abort().
++ *
+  * @mr: the #MemoryRegion to be initialized.
+  * @owner: the object that tracks the region's reference count
+  * @ops: callbacks for write access handling.
+@@ -459,16 +462,21 @@ void memory_region_init_rom_device(Memor
+  * A reservation region primariy serves debugging purposes.  It claims I/O
+  * space that is not supposed to be handled by QEMU itself.  Any access via
+  * the memory API will cause an abort().
++ * This function is deprecated. Use memory_region_init_io() with NULL
++ * callbacks instead.
+  *
+  * @mr: the #MemoryRegion to be initialized
+  * @owner: the object that tracks the region's reference count
+  * @name: used for debugging; not visible to the user or ABI
+  * @size: size of the region.
+  */
+-void memory_region_init_reservation(MemoryRegion *mr,
+-                                    struct Object *owner,
++static inline void memory_region_init_reservation(MemoryRegion *mr,
++                                    Object *owner,
+                                     const char *name,
+-                                    uint64_t size);
++                                    uint64_t size)
++{
++    memory_region_init_io(mr, owner, NULL, mr, name, size);
++}
+ 
+ /**
+  * memory_region_init_iommu: Initialize a memory region that translates
+Index: qemu-2.4+dfsg/memory.c
+===================================================================
+--- qemu-2.4+dfsg.orig/memory.c
++++ qemu-2.4+dfsg/memory.c
+@@ -1182,7 +1182,7 @@ void memory_region_init_io(MemoryRegion
+                            uint64_t size)
+ {
+     memory_region_init(mr, owner, name, size);
+-    mr->ops = ops;
++    mr->ops = ops ? ops : &unassigned_mem_ops;
+     mr->opaque = opaque;
+     mr->terminates = true;
+ }
+@@ -1300,14 +1300,6 @@ void memory_region_init_iommu(MemoryRegi
+     notifier_list_init(&mr->iommu_notify);
+ }
+ 
+-void memory_region_init_reservation(MemoryRegion *mr,
+-                                    Object *owner,
+-                                    const char *name,
+-                                    uint64_t size)
+-{
+-    memory_region_init_io(mr, owner, &unassigned_mem_ops, mr, name, size);
+-}
+-
+ static void memory_region_finalize(Object *obj)
+ {
+     MemoryRegion *mr = MEMORY_REGION(obj);
diff -Nru qemu-2.4+dfsg/debian/patches/series qemu-2.4+dfsg/debian/patches/series
--- qemu-2.4+dfsg/debian/patches/series	2015-09-15 10:28:56.000000000 -0600
+++ qemu-2.4+dfsg/debian/patches/series	2015-10-06 16:43:03.000000000 -0600
@@ -8,3 +8,11 @@
 ide-fix-ATAPI-command-permissions-CVE-2015-6855.patch
 ne2000-add-checks-to-validate-ring-buffer-pointers-CVE-2015-5279.patch
 ne2000-avoid-infinite-loop-when-receiving-packets-CVE-2015-5278.patch
+Merge-memory_region_init_reservation-into-memory_reg.patch
+hw-arm-gic-Kill-code-duplication.patch
+Introduce-gic_class_name-instead-of-repeating-condit.patch
+hw-intc-Implement-GIC-500-base-class.patch
+intc-gic-Extract-some-reusable-vGIC-code.patch
+arm_kvm-Do-not-assume-particular-GIC-type-in-kvm_arc.patch
+hw-intc-Initial-implementation-of-vGICv3.patch
+hw-arm-virt-Add-gic-version-option-to-virt-machine.patch

Reply via email to