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).

+        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?
+        exit(1);
+    }

+}
Conditional to not using qemu_get_cpu():
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>


Reply via email to