diff mbox

[RFC,V5,9/9] hw/arm: Add virt-v3 machine that uses GIC-500

Message ID 1445361732-16257-10-git-send-email-shlomopongratz@gmail.com
State New
Headers show

Commit Message

Shlomo Pongratz Oct. 20, 2015, 5:22 p.m. UTC
From: Shlomo Pongratz <shlomo.pongratz@huawei.com>

Add virt-v3 machine that uses GIC-500.
Registers the CPU system instructions and bind them to the GIC.
Pass the cores' affinity to the GIC.

Signed-off-by: Shlomo Pongratz <shlomo.pongratz@huawei.com>
---
 hw/arm/virt.c         | 87 ++++++++++++++++++++++++++++++++++++++++++++++-----
 include/hw/arm/fdt.h  |  2 ++
 include/hw/arm/virt.h |  1 +
 target-arm/machine.c  |  7 ++++-
 4 files changed, 88 insertions(+), 9 deletions(-)

Comments

Pavel Fedin Oct. 21, 2015, 7:02 a.m. UTC | #1
Hello!

> -----Original Message-----
> From: Shlomo Pongratz [mailto:shlomopongratz@gmail.com]
> Sent: Tuesday, October 20, 2015 8:22 PM
> To: qemu-devel@nongnu.org
> Cc: p.fedin@samsung.com; peter.maydell@linaro.org; eric.auger@linaro.org;
> shannon.zhao@linaro.org; imammedo@redhat.com; ashoks@broadcom.com; Shlomo Pongratz
> Subject: [PATCH RFC V5 9/9] hw/arm: Add virt-v3 machine that uses GIC-500
> 
> From: Shlomo Pongratz <shlomo.pongratz@huawei.com>
> 
> Add virt-v3 machine that uses GIC-500.

 We already concluded long time ago that adding virt-v3 machine is wrong approach. We already have gic-version property for the virt
machine, and especially for you i left a TODO placeholder in gicv3_class_name() function. Just return name of your class there, and
you're done.

> Registers the CPU system instructions and bind them to the GIC.
> Pass the cores' affinity to the GIC.
> 
> Signed-off-by: Shlomo Pongratz <shlomo.pongratz@huawei.com>
> ---
>  hw/arm/virt.c         | 87 ++++++++++++++++++++++++++++++++++++++++++++++-----
>  include/hw/arm/fdt.h  |  2 ++
>  include/hw/arm/virt.h |  1 +
>  target-arm/machine.c  |  7 ++++-
>  4 files changed, 88 insertions(+), 9 deletions(-)
> 
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index 5d38c47..d4fb8f3 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   MACHINE_TYPE_NAME("virt")
> +#define TYPE_VIRTV3_MACHINE MACHINE_TYPE_NAME("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 */

 Memory map of the "virt" machine already contains everything needed. BTW, what's "SPI"? "MBI", you meant? Well, we are going to
have an ITS, so this simple message translator will not be needed.

>      [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");
> @@ -429,12 +441,32 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool
> secure)
>      gicdev = qdev_create(NULL, gictype);
>      qdev_prop_set_uint32(gicdev, "revision", type);
>      qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
> +
> +#ifdef TARGET_AARCH64
> +    if (type == 3) {
> +        qdev_prop_set_uint32(gicdev, "len-mp-affinity", smp_cpus);
> +        /* Connect GIC to CPU */
> +        for (i = 0; i < smp_cpus; i++) {
> +            char *propname;
> +            CPUState *cpu = qemu_get_cpu(i);
> +            ARMCPU *armcpu = ARM_CPU(cpu);
> +            propname = g_strdup_printf("mp-affinity[%d]", i);
> +            qdev_prop_set_uint64(gicdev, propname, armcpu->mp_affinity);
> +            g_free(propname);
> +        }
> +    }
> +#endif
>      /* Note that the num-irq property counts both internal and external
>       * interrupts; there are always 32 of the former (mandated by GIC spec).
>       */
>      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 +477,16 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool
> secure)
>          sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base);
>      }
> 
> +#ifdef TARGET_AARCH64
> +    if (type == 3) {
> +        /* Connect GIC to CPU */
> +        for (i = 0; i < smp_cpus; i++) {
> +            CPUState *cpu = qemu_get_cpu(i);
> +            aarch64_registers_with_opaque_set(OBJECT(cpu), (void *)gicdev);
> +        }
> +    }
> +#endif
> +
>      /* 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 +508,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));
> @@ -967,7 +1009,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;
> @@ -1116,7 +1158,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);
> 
> @@ -1140,8 +1182,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",
> @@ -1149,6 +1190,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);
> @@ -1174,9 +1221,33 @@ 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;
> +}
> +
> +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);
>  }

 As i said before, this stuff is simply not needed.

> 
>  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";

 Peter told me, there is a policy to use dash ("-") in class names. So "arm-gicv3".
 By the way, why does it depend on TARGET_AARCH64? Actually, TARGET_ARM and TARGET_AARCH64 are the same. You can make both emulators
running both 64- and 32-bit code. KVM code depends on TARGET_AARCH64 only because some definitions are missing on 32-bit kernels.
You don't have this restriction, so you don't need this #ifdef.

> +#else
> +        error_report("KVM GICv3 acceleration is not supported on this "
> +                     "platform\n");

 Why "KVM" here? Well, rubbish anyway because of the above. :)

> +#endif
>      }
> 
>      exit(1);
> --
> 1.9.1

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia
Shlomo Pongratz Oct. 21, 2015, 8:52 a.m. UTC | #2
See inline.

On Wednesday, October 21, 2015, Pavel Fedin <p.fedin@samsung.com> wrote:

>  Hello!
>
> > -----Original Message-----
> > From: Shlomo Pongratz [mailto:shlomopongratz@gmail.com <javascript:;>]
> > Sent: Tuesday, October 20, 2015 8:22 PM
> > To: qemu-devel@nongnu.org <javascript:;>
> > Cc: p.fedin@samsung.com <javascript:;>; peter.maydell@linaro.org
> <javascript:;>; eric.auger@linaro.org <javascript:;>;
> > shannon.zhao@linaro.org <javascript:;>; imammedo@redhat.com
> <javascript:;>; ashoks@broadcom.com <javascript:;>; Shlomo Pongratz
> > Subject: [PATCH RFC V5 9/9] hw/arm: Add virt-v3 machine that uses GIC-500
> >
> > From: Shlomo Pongratz <shlomo.pongratz@huawei.com <javascript:;>>
> >
> > Add virt-v3 machine that uses GIC-500.
>
>  We already concluded long time ago that adding virt-v3 machine is wrong
> approach. We already have gic-version property for the virt
> machine, and especially for you i left a TODO placeholder in
> gicv3_class_name() function. Just return name of your class there, and
> you're done.
>
>
I see, just how do I pass the gic version from the command line?


> > Registers the CPU system instructions and bind them to the GIC.
> > Pass the cores' affinity to the GIC.
> >
> > Signed-off-by: Shlomo Pongratz <shlomo.pongratz@huawei.com
> <javascript:;>>
> > ---
> >  hw/arm/virt.c         | 87
> ++++++++++++++++++++++++++++++++++++++++++++++-----
> >  include/hw/arm/fdt.h  |  2 ++
> >  include/hw/arm/virt.h |  1 +
> >  target-arm/machine.c  |  7 ++++-
> >  4 files changed, 88 insertions(+), 9 deletions(-)
> >
> > diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> > index 5d38c47..d4fb8f3 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   MACHINE_TYPE_NAME("virt")
> > +#define TYPE_VIRTV3_MACHINE MACHINE_TYPE_NAME("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 */
>
>  Memory map of the "virt" machine already contains everything needed. BTW,
> what's "SPI"? "MBI", you meant? Well, we are going to
> have an ITS, so this simple message translator will not be needed.
>
Typo.

>
> >      [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");
> > @@ -429,12 +441,32 @@ static void create_gic(VirtBoardInfo *vbi,
> qemu_irq *pic, int type, bool
> > secure)
> >      gicdev = qdev_create(NULL, gictype);
> >      qdev_prop_set_uint32(gicdev, "revision", type);
> >      qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
> > +
> > +#ifdef TARGET_AARCH64
> > +    if (type == 3) {
> > +        qdev_prop_set_uint32(gicdev, "len-mp-affinity", smp_cpus);
> > +        /* Connect GIC to CPU */
> > +        for (i = 0; i < smp_cpus; i++) {
> > +            char *propname;
> > +            CPUState *cpu = qemu_get_cpu(i);
> > +            ARMCPU *armcpu = ARM_CPU(cpu);
> > +            propname = g_strdup_printf("mp-affinity[%d]", i);
> > +            qdev_prop_set_uint64(gicdev, propname, armcpu->mp_affinity);
> > +            g_free(propname);
> > +        }
> > +    }
> > +#endif
> >      /* Note that the num-irq property counts both internal and external
> >       * interrupts; there are always 32 of the former (mandated by GIC
> spec).
> >       */
> >      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 +477,16 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq
> *pic, int type, bool
> > secure)
> >          sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base);
> >      }
> >
> > +#ifdef TARGET_AARCH64
> > +    if (type == 3) {
> > +        /* Connect GIC to CPU */
> > +        for (i = 0; i < smp_cpus; i++) {
> > +            CPUState *cpu = qemu_get_cpu(i);
> > +            aarch64_registers_with_opaque_set(OBJECT(cpu), (void
> *)gicdev);
> > +        }
> > +    }
> > +#endif
> > +
> >      /* 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 +508,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));
> > @@ -967,7 +1009,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;
> > @@ -1116,7 +1158,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);
> >
> > @@ -1140,8 +1182,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",
> > @@ -1149,6 +1190,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);
> > @@ -1174,9 +1221,33 @@ 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;
> > +}
> > +
> > +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);
> >  }
>
>  As i said before, this stuff is simply not needed.
>
> >
> >  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";
>
>  Peter told me, there is a policy to use dash ("-") in class names. So
> "arm-gicv3".
>  By the way, why does it depend on TARGET_AARCH64? Actually, TARGET_ARM
> and TARGET_AARCH64 are the same. You can make both emulators
> running both 64- and 32-bit code. KVM code depends on TARGET_AARCH64 only
> because some definitions are missing on 32-bit kernels.
> You don't have this restriction, so you don't need this #ifdef.
>

O.K. I'll change to dash.
GICV3 is accessed by system instructions that exists only in ARCH64.


> > +#else
> > +        error_report("KVM GICv3 acceleration is not supported on this "
> > +                     "platform\n");
>
>  Why "KVM" here? Well, rubbish anyway because of the above. :)
>
> > +#endif
> >      }
> >
> >      exit(1);
> > --
> > 1.9.1
>
> Kind regards,
> Pavel Fedin
> Expert Engineer
> Samsung Electronics Research center Russia
>
>
Pavel Fedin Oct. 21, 2015, 10:30 a.m. UTC | #3
Hello!

> I see, just how do I pass the gic version from the command line?

 Easy. -machine virt,gic-version=3

> GICV3 is accessed by system instructions that exists only in ARCH64.

 Wrong. In 32-bit mode the CPU sees them as CP15 registers. See "8.5 AArch32 System register descriptions".
 I would say, system registers are nothing new, these are just renamed CP15 registers, with "CPn" prefix removed.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia
Shlomo Pongratz Oct. 21, 2015, 11:33 a.m. UTC | #4
See inline

On Wednesday, October 21, 2015, Pavel Fedin <p.fedin@samsung.com> wrote:

>  Hello!
>
> > I see, just how do I pass the gic version from the command line?
>
>  Easy. -machine virt,gic-version=3
>
> > GICV3 is accessed by system instructions that exists only in ARCH64.
>
>  Wrong. In 32-bit mode the CPU sees them as CP15 registers. See "8.5
> AArch32 System register descriptions".
>  I would say, system registers are nothing new, these are just renamed
> CP15 registers, with "CPn" prefix removed.
>

I assume I can add the system registers to target-arm/cpu.c but I wonder if
someone really needs to simulate more than 8 AArch32 CPU(s)


> Kind regards,
> Pavel Fedin
> Expert Engineer
> Samsung Electronics Research center Russia
>
>
>
Peter Maydell Oct. 21, 2015, 12:24 p.m. UTC | #5
On 21 October 2015 at 12:33, Shlomo Pongratz <shlomopongratz@gmail.com> wrote:
> I assume I can add the system registers to target-arm/cpu.c but I wonder if
> someone really needs to simulate more than 8 AArch32 CPU(s)

The system register implementation belongs in the gic code, not
target-arm/. We already have support for devices that say
"I have some system registers, please add them to this CPU".

The mechanism is the same for system registers for both 32-bit
and 64-bit, incidentally.

thanks
-- PMM
Shlomo Pongratz Oct. 21, 2015, 1:01 p.m. UTC | #6
On Wednesday, October 21, 2015, Peter Maydell <peter.maydell@linaro.org>
wrote:

> On 21 October 2015 at 12:33, Shlomo Pongratz <shlomopongratz@gmail.com
> <javascript:;>> wrote:
> > I assume I can add the system registers to target-arm/cpu.c but I wonder
> if
> > someone really needs to simulate more than 8 AArch32 CPU(s)
>
> The system register implementation belongs in the gic code, not
> target-arm/. We already have support for devices that say
> "I have some system registers, please add them to this CPU".
>
>
I don't understand.
The system registers are defined in ARM Architecture reference Manual.
It is true that the real implementation is in arm_gicv3_interrupts.c
But the crn, crm, op0, and op1 of the instructions are in CPU domain.


> The mechanism is the same for system registers for both 32-bit
> and 64-bit, incidentally.
>
> I agree.


> thanks
> -- PMM
>
Peter Maydell Oct. 21, 2015, 1:24 p.m. UTC | #7
On 21 October 2015 at 14:01, Shlomo Pongratz <shlomopongratz@gmail.com> wrote:
> On Wednesday, October 21, 2015, Peter Maydell <peter.maydell@linaro.org>
> wrote:
>> The system register implementation belongs in the gic code, not
>> target-arm/. We already have support for devices that say
>> "I have some system registers, please add them to this CPU".
>>
>
> I don't understand.
> The system registers are defined in ARM Architecture reference Manual.
> It is true that the real implementation is in arm_gicv3_interrupts.c
> But the crn, crm, op0, and op1 of the instructions are in CPU domain.

Well, this comes down to "do you want to design the GICv3
emulation to preserve the split the hardware has between
the cpu interface and the GIC proper". In hardware there's
actually a defined protocol between the two, so you can
have CPUs from one implementor that talk to a GIC from
another implementor. For QEMU that seems like overkill,
as we will only ever have one GICv3 implementation and one
CPU implementation. So we should just have the GICv3
provide the CPU system register implementations. But the
code for those belongs in hw/intc/: that should call
the function for "add these system registers" which we
have already: define_arm_cp_regs_with_opaque().
(We use this in hw/arm/pxa2xx_pic, for instance.)

thanks
-- PMM
Pavel Fedin Oct. 21, 2015, 1:26 p.m. UTC | #8
Hello!

>> The system register implementation belongs in the gic code, not
>> target-arm/. We already have support for devices that say
>> "I have some system registers, please add them to this CPU".

> I don't understand.
> The system registers are defined in ARM Architecture reference Manual.
> It is true that the real implementation is in arm_gicv3_interrupts.c
> But the crn, crm, op0, and op1 of the instructions are in CPU domain.

 Not really. If you take a closer look, you'll see that crn, crm, op1, op2 are the same for both ARM64 and ARM32. The only difference is that ARM64 uses op0 = 3, and ARM32 uses cp = 15. Both of these specifiers can coexist in the descriptor table.
 I think Peter wants to tell that you should not insert your register table and registration function into target-arm/cpu64.c. This code should go to hw/intc/arm_gicv3_cpu_interface.c, add .cp = 15, and - voila - it magically works with both ARM32 and ARM64.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia
Shlomo Pongratz Oct. 21, 2015, 2:05 p.m. UTC | #9
O.K.

On Wednesday, October 21, 2015, Pavel Fedin <p.fedin@samsung.com> wrote:

>  Hello!
>
> >> The system register implementation belongs in the gic code, not
> >> target-arm/. We already have support for devices that say
> >> "I have some system registers, please add them to this CPU".
>
> > I don't understand.
> > The system registers are defined in ARM Architecture reference Manual.
> > It is true that the real implementation is in arm_gicv3_interrupts.c
> > But the crn, crm, op0, and op1 of the instructions are in CPU domain.
>
>  Not really. If you take a closer look, you'll see that crn, crm, op1, op2
> are the same for both ARM64 and ARM32. The only difference is that ARM64
> uses op0 = 3, and ARM32 uses cp = 15. Both of these specifiers can coexist
> in the descriptor table.
>  I think Peter wants to tell that you should not insert your register
> table and registration function into target-arm/cpu64.c. This code should
> go to hw/intc/arm_gicv3_cpu_interface.c, add .cp = 15, and - voila - it
> magically works with both ARM32 and ARM64.
>
> Kind regards,
> Pavel Fedin
> Expert Engineer
> Samsung Electronics Research center Russia
>
>
>
diff mbox

Patch

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 5d38c47..d4fb8f3 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   MACHINE_TYPE_NAME("virt")
+#define TYPE_VIRTV3_MACHINE MACHINE_TYPE_NAME("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");
@@ -429,12 +441,32 @@  static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure)
     gicdev = qdev_create(NULL, gictype);
     qdev_prop_set_uint32(gicdev, "revision", type);
     qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
+
+#ifdef TARGET_AARCH64
+    if (type == 3) {
+        qdev_prop_set_uint32(gicdev, "len-mp-affinity", smp_cpus);
+        /* Connect GIC to CPU */
+        for (i = 0; i < smp_cpus; i++) {
+            char *propname;
+            CPUState *cpu = qemu_get_cpu(i);
+            ARMCPU *armcpu = ARM_CPU(cpu);
+            propname = g_strdup_printf("mp-affinity[%d]", i);
+            qdev_prop_set_uint64(gicdev, propname, armcpu->mp_affinity);
+            g_free(propname);
+        }
+    }
+#endif
     /* Note that the num-irq property counts both internal and external
      * interrupts; there are always 32 of the former (mandated by GIC spec).
      */
     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 +477,16 @@  static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure)
         sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base);
     }
 
+#ifdef TARGET_AARCH64
+    if (type == 3) {
+        /* Connect GIC to CPU */
+        for (i = 0; i < smp_cpus; i++) {
+            CPUState *cpu = qemu_get_cpu(i);
+            aarch64_registers_with_opaque_set(OBJECT(cpu), (void *)gicdev);
+        }
+    }
+#endif
+
     /* 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 +508,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));
@@ -967,7 +1009,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;
@@ -1116,7 +1158,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);
 
@@ -1140,8 +1182,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",
@@ -1149,6 +1190,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);
@@ -1174,9 +1221,33 @@  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;
+}
+
+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);