Hi Philippe,
On Fri, Sep 4, 2026 at 12:56 AM Philippe Mathieu-Daudé
<[email protected]> wrote:
>
> On 3/9/26 13:24, Bin Meng wrote:
> > Add the base topology for the Phytium Pi board built around the
> > E2000Q SoC, with two FTC310 and two FTC664 CPUs, RAM, GICv3/ITS,
> > and PL011 UARTs.
> >
> > Describe the CPUs as three non-uniform clusters matching the vendor
> > Linux device tree. Preserve the board CPU slot order so firmware
> > MPIDR 0x200 maps to QEMU CPU index 2.
> >
> > Signed-off-by: Bin Meng <[email protected]>
> > ---
> >
> > hw/arm/Kconfig | 8 +
> > hw/arm/meson.build | 1 +
> > hw/arm/phytium_e2000.c | 406 +++++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 415 insertions(+)
> > create mode 100644 hw/arm/phytium_e2000.c
>
>
> > +struct PhytiumE2000State {
> > + MachineState parent;
> > + struct arm_boot_info bootinfo;
> > + DeviceState *gic;
> > + MemoryRegion ram_low;
> > + MemoryRegion ram_high;
> > +};
>
>
> > +static void phytium_e2000_create_gic(PhytiumE2000State *s)
> > +{
> > + MachineState *ms = MACHINE(s);
> > + SysBusDevice *gicbusdev;
> > + QList *redist_region_count;
> > + int i;
> > +
> > + s->gic = qdev_new(gicv3_class_name());
> > + qdev_prop_set_uint32(s->gic, "revision", 3);
> > + qdev_prop_set_uint32(s->gic, "num-cpu", ms->smp.cpus);
> > + qdev_prop_set_uint32(s->gic, "num-irq", PHYTIUM_E2000_NUM_IRQS + 32);
> > + qdev_prop_set_bit(s->gic, "has-security-extensions", true);
> > + qdev_prop_set_bit(s->gic, "has-lpi", true);
> > +
> > + redist_region_count = qlist_new();
> > + qlist_append_int(redist_region_count, ms->smp.cpus);
> > + qdev_prop_set_array(s->gic, "redist-region-count",
> > redist_region_count);
> > +
> > + object_property_set_link(OBJECT(s->gic), "sysmem",
> > + OBJECT(get_system_memory()), &error_fatal);
> > +
> > + gicbusdev = SYS_BUS_DEVICE(s->gic);
> > + sysbus_realize_and_unref(gicbusdev, &error_fatal);
> > + sysbus_mmio_map(gicbusdev, 0,
> > + phytium_e2000_memmap[PHYTIUM_E2000_GIC_DIST].base);
> > + sysbus_mmio_map(gicbusdev, 1,
> > + phytium_e2000_memmap[PHYTIUM_E2000_GIC_REDIST].base);
> > +
> > + for (i = 0; i < ms->smp.cpus; i++) {
> > + DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
>
> I'd rather you keep a reference in PhytiumE2000State when creating
> in [*] and access the CPUs that way, not with qemu_get_cpu() (because
> we plan to restrict it to accel/, as it is problematic on heterogeneous
> emulation).
Will fix in v2.
>
> > + int intidbase = PHYTIUM_E2000_NUM_IRQS + i * GIC_INTERNAL;
> > + static const int timer_irq[] = {
> > + [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
> > + [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
> > + [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
> > + [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
> > + };
> > +
> > + for (int irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
> > + qdev_connect_gpio_out(cpudev, irq,
> > + qdev_get_gpio_in(s->gic, intidbase + timer_irq[irq]));
> > + }
> > + qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
> > 0,
> > + qdev_get_gpio_in(s->gic, intidbase + ARCH_GIC_MAINT_IRQ));
> > + qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
> > + qdev_get_gpio_in(s->gic, intidbase + VIRTUAL_PMU_IRQ));
> > +
> > + sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev,
> > ARM_CPU_IRQ));
> > + sysbus_connect_irq(gicbusdev, i + ms->smp.cpus,
> > + qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
> > + sysbus_connect_irq(gicbusdev, i + 2 * ms->smp.cpus,
> > + qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
> > + sysbus_connect_irq(gicbusdev, i + 3 * ms->smp.cpus,
> > + qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
> > + }
> > +
> > + phytium_e2000_create_its(s);
> > +}
>
>
> > +static void phytium_e2000_create_cpus(PhytiumE2000State *s)
> > +{
> > + MachineState *ms = MACHINE(s);
> > + const CPUArchIdList *possible_cpus;
> > + int i;
> > +
> > + possible_cpus = MACHINE_GET_CLASS(ms)->possible_cpu_arch_ids(ms);
> > +
> > + for (i = 0; i < ms->smp.cpus; i++) {
> > + Object *cpuobj = object_new(possible_cpus->cpus[i].type);
>
> [*]
>
> > + CPUState *cs;
> > +
> > + object_property_set_int(cpuobj, "mp-affinity",
> > + possible_cpus->cpus[i].arch_id,
> > + &error_abort);
> > + object_property_set_int(cpuobj, "cntfrq", PHYTIUM_E2000_GTIMER_HZ,
> > + &error_abort);
> > + if (object_property_find(cpuobj, "has_el3")) {
> > + /*
> > + * The generic-loader U-Boot path starts after the EL3 firmware
> > + * stages that normally provide the Phytium SMC services.
> > + */
> > + object_property_set_bool(cpuobj, "has_el3", false,
> > &error_abort);
> > + }
> > + object_property_set_link(cpuobj, "memory",
> > OBJECT(get_system_memory()),
> > + &error_abort);
> > + cs = CPU(cpuobj);
> > + cs->cpu_index = i;
> > + qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
> > + object_unref(cpuobj);
> > + }
> > +}
> > +
> > +static void phytium_pi_init(MachineState *ms)
> > +{
> > + PhytiumE2000State *s = PHYTIUM_PI(ms);
> > + int i;
> > +
> > + if (kvm_enabled()) {
> > + error_report("phytium-pi: KVM is not supported");
>
> Why is it relevant?
This is because the machine relies on heterogeneous named
FTC310/FTC664 TCG CPU models and Arm KVM generally requires the host
CPU model. KVM is rejected explicitly instead of failing later during
vCPU initialization.
> > + exit(1);
> > + }
>
> > +}
> Conditional to not using qemu_get_cpu():
> Reviewed-by: Philippe Mathieu-Daudé <[email protected]>
Thanks for the review!
Regards,
Bin