From: Pavel Fedin <p.fe...@samsung.com> I would like to offer this, slightly improved implementation. The key thing is a new kernel_irqchip_type member in Machine class. Currently it it used only by virt machine for its internal purposes, however in future it is to be passed to KVM in kvm_irqchip_create(). The variable is defined as int in order to be architecture agnostic, for potential future users.
Signed-off-by: Pavel Fedin <p.fe...@samsung.com> --- hw/arm/virt.c | 72 +++++++++++++++++++++++++++++++++++++++++++++------ include/hw/arm/fdt.h | 2 ++ include/hw/arm/virt.h | 1 + target-arm/machine.c | 7 ++++- 4 files changed, 73 insertions(+), 9 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 4d15309..4c2ae7f 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -71,6 +71,7 @@ typedef struct VirtBoardInfo { uint32_t clock_phandle; uint32_t gic_phandle; uint32_t v2m_phandle; + const char *class_name; } VirtBoardInfo; typedef struct { @@ -86,6 +87,7 @@ typedef struct { } VirtMachineState; #define TYPE_VIRT_MACHINE "virt" +#define TYPE_VIRTV3_MACHINE "virt-v3" #define VIRT_MACHINE(obj) \ OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE) #define VIRT_MACHINE_GET_CLASS(obj) \ @@ -111,6 +113,7 @@ static const MemMapEntry a15memmap[] = { [VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 }, /* GIC distributor and CPU interfaces sit inside the CPU peripheral space */ [VIRT_GIC_DIST] = { 0x08000000, 0x00010000 }, + /* Note on GICv3 VIRT_GIC_DIST_SPI takes place of VIRT_GIC_CPU */ [VIRT_GIC_CPU] = { 0x08010000, 0x00010000 }, [VIRT_GIC_V2M] = { 0x08020000, 0x00001000 }, /* The space in between here is reserved for GICv3 CPU/vCPU/HYP */ @@ -145,21 +148,26 @@ static VirtBoardInfo machines[] = { .cpu_model = "cortex-a15", .memmap = a15memmap, .irqmap = a15irqmap, + .class_name = TYPE_ARM_CPU, + }, { .cpu_model = "cortex-a53", .memmap = a15memmap, .irqmap = a15irqmap, + .class_name = TYPE_AARCH64_CPU, }, { .cpu_model = "cortex-a57", .memmap = a15memmap, .irqmap = a15irqmap, + .class_name = TYPE_AARCH64_CPU, }, { .cpu_model = "host", .memmap = a15memmap, .irqmap = a15irqmap, + .class_name = TYPE_ARM_CPU, }, }; @@ -228,7 +236,6 @@ static void fdt_add_psci_node(const VirtBoardInfo *vbi) if (armcpu->psci_version == 2) { const char comp[] = "arm,psci-0.2\0arm,psci"; qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp)); - cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF; if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) { cpu_suspend_fn = QEMU_PSCI_0_2_FN64_CPU_SUSPEND; @@ -241,7 +248,6 @@ static void fdt_add_psci_node(const VirtBoardInfo *vbi) } } else { qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci"); - cpu_suspend_fn = QEMU_PSCI_0_1_FN_CPU_SUSPEND; cpu_off_fn = QEMU_PSCI_0_1_FN_CPU_OFF; cpu_on_fn = QEMU_PSCI_0_1_FN_CPU_ON; @@ -274,6 +280,12 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi, int gictype) irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, GIC_FDT_IRQ_PPI_CPU_WIDTH, (1 << vbi->smp_cpus) - 1); + } else if (gictype == 3) { + uint32_t max; + /* Argument is 32 bit but 8 bits are reserved for flags */ + max = (vbi->smp_cpus >= 24) ? 24 : vbi->smp_cpus; + irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, + GICV3_FDT_IRQ_PPI_CPU_WIDTH, (1 << max) - 1); } qemu_fdt_add_subnode(vbi->fdt, "/timer"); @@ -434,7 +446,12 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure) */ qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32); if (!kvm_irqchip_in_kernel()) { - qdev_prop_set_bit(gicdev, "has-security-extensions", secure); + if (type == 3) { + /* AARCH64 has 4 security levels */ + qdev_prop_set_uint8(gicdev, "security-levels", secure ? 1 : 0); + } else { + qdev_prop_set_bit(gicdev, "has-security-extensions", secure); + } } qdev_init_nofail(gicdev); gicbusdev = SYS_BUS_DEVICE(gicdev); @@ -445,6 +462,14 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure) sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base); } + if (type == 3) { + /* Connect GIC to CPU */ + for (i = 0; i < smp_cpus; i++) { + CPUState *cpu = qemu_get_cpu(i); + aatch64_registers_with_opaque_set(OBJECT(cpu), (void *)gicdev); + } + } + /* Wire the outputs from each CPU's generic timer to the * appropriate GIC PPI inputs, and the GIC's IRQ output to * the CPU's IRQ input. @@ -466,7 +491,7 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure) for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { qdev_connect_gpio_out(cpudev, irq, qdev_get_gpio_in(gicdev, - ppibase + timer_irq[irq])); + ppibase + timer_irq[irq])); } sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); @@ -962,7 +987,7 @@ static void machvirt_init(MachineState *machine) create_fdt(vbi); for (n = 0; n < smp_cpus; n++) { - ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]); + ObjectClass *oc = cpu_class_by_name(vbi->class_name, cpustr[0]); CPUClass *cc = CPU_CLASS(oc); Object *cpuobj; Error *err = NULL; @@ -1111,7 +1136,7 @@ static void virt_set_gic_version(Object *obj, const char *value, Error **errp) } } -static void virt_instance_init(Object *obj) +static void virt_instance_init_common(Object *obj, int32_t version) { VirtMachineState *vms = VIRT_MACHINE(obj); @@ -1135,8 +1160,7 @@ static void virt_instance_init(Object *obj) "Set on/off to enable/disable using " "physical address space above 32 bits", NULL); - /* Default GIC type is v2 */ - vms->gic_version = 2; + vms->gic_version = version; object_property_add_str(obj, "gic-version", virt_get_gic_version, virt_set_gic_version, NULL); object_property_set_description(obj, "gic-version", @@ -1144,6 +1168,12 @@ static void virt_instance_init(Object *obj) "Valid values are 2, 3 and host", NULL); } +static void virt_instance_init(Object *obj) +{ + /* Default GIC type is v2 */ + virt_instance_init_common(obj, 2); +} + static void virt_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -1169,9 +1199,35 @@ static const TypeInfo machvirt_info = { .class_init = virt_class_init, }; +static void virtv3_instance_init(Object *obj) +{ + virt_instance_init_common(obj, 3); +} + +static void virtv3_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->name = TYPE_VIRTV3_MACHINE; + mc->desc = "ARM Virtual Machine with GICv3", + mc->init = machvirt_init; + /* With gic3 full implementation (with bitops) rase the lmit to 128 */ + mc->max_cpus = 64; +} + +static const TypeInfo machvirtv3_info = { + .name = TYPE_VIRTV3_MACHINE, + .parent = TYPE_VIRT_MACHINE, + .instance_size = sizeof(VirtMachineState), + .instance_init = virtv3_instance_init, + .class_size = sizeof(VirtMachineClass), + .class_init = virtv3_class_init, +}; + static void machvirt_machine_init(void) { type_register_static(&machvirt_info); + type_register_static(&machvirtv3_info); } machine_init(machvirt_machine_init); diff --git a/include/hw/arm/fdt.h b/include/hw/arm/fdt.h index c3d5015..ad8f85c 100644 --- a/include/hw/arm/fdt.h +++ b/include/hw/arm/fdt.h @@ -30,5 +30,7 @@ #define GIC_FDT_IRQ_PPI_CPU_START 8 #define GIC_FDT_IRQ_PPI_CPU_WIDTH 8 +#define GICV3_FDT_IRQ_PPI_CPU_WIDTH 24 + #endif diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index f464586..53ff50a 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -46,6 +46,7 @@ enum { VIRT_CPUPERIPHS, VIRT_GIC_DIST, VIRT_GIC_CPU, + VIRT_GIC_DIST_SPI = VIRT_GIC_CPU, VIRT_GIC_V2M, VIRT_GIC_ITS, VIRT_GIC_REDIST, diff --git a/target-arm/machine.c b/target-arm/machine.c index 36a0d15..33f28be 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -341,7 +341,12 @@ const char *gicv3_class_name(void) #endif } else { /* TODO: Software emulation is not implemented yet */ - error_report("KVM is currently required for GICv3 emulation\n"); +#ifdef TARGET_AARCH64 + return "arm_gicv3"; +#else + error_report("KVM GICv3 acceleration is not supported on this " + "platform\n"); +#endif } exit(1); -- 1.9.1