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