On 12. 1. 26. 06:42, Alistair Francis wrote:
> CAUTION: This email originated from outside of the organization. Do not click
> links or open attachments unless you recognize the sender and know the
> content is safe.
>
>
> On Thu, Jan 8, 2026 at 11:41 PM Djordje Todorovic
> <[email protected]> wrote:
>> Add support for the Coherent Processing System for RISC-V.
>> This enables SMP support for RISC-V boards that require
>> cache-coherent multiprocessor systems.
>>
>> Signed-off-by: Chao-ying Fu <[email protected]>
>> Signed-off-by: Djordje Todorovic <[email protected]>
>> Acked-by: Daniel Henrique Barboza <[email protected]>
>> ---
>> hw/misc/Kconfig | 4 +
>> hw/riscv/cps.c | 196 +++++++++++++++++++++++++++++++++++++++++
>> hw/riscv/meson.build | 2 +
>> include/hw/riscv/cps.h | 66 ++++++++++++++
>> 4 files changed, 268 insertions(+)
>> create mode 100644 hw/riscv/cps.c
>> create mode 100644 include/hw/riscv/cps.h
>>
>> diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
>> index 38be72b141..4a22d68233 100644
>> --- a/hw/misc/Kconfig
>> +++ b/hw/misc/Kconfig
>> @@ -127,12 +127,16 @@ config RISCV_MIPS_CMGCR
>> config RISCV_MIPS_CPC
>> bool
>>
>> +config RISCV_MIPS_CPS
>> + bool
>> +
>> config MIPS_BOSTON_AIA
>> bool
>> default y
>> depends on RISCV64
>> select RISCV_MIPS_CMGCR
>> select RISCV_MIPS_CPC
>> + select RISCV_MIPS_CPS
>>
>> config MPS2_FPGAIO
>> bool
>> diff --git a/hw/riscv/cps.c b/hw/riscv/cps.c
>> new file mode 100644
>> index 0000000000..86172be5b3
>> --- /dev/null
>> +++ b/hw/riscv/cps.c
>> @@ -0,0 +1,196 @@
>> +/*
>> + * Coherent Processing System emulation.
>> + *
>> + * Copyright (c) 2016 Imagination Technologies
>> + *
>> + * Copyright (c) 2025 MIPS
>> + *
>> + * SPDX-License-Identifier: GPL-2.0-or-later
>> + *
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qapi/error.h"
>> +#include "qemu/module.h"
>> +#include "hw/riscv/cps.h"
>> +#include "hw/core/qdev-properties.h"
>> +#include "system/reset.h"
>> +#include "hw/intc/riscv_aclint.h"
>> +#include "hw/intc/riscv_aplic.h"
>> +#include "hw/intc/riscv_imsic.h"
>> +#include "hw/pci/msi.h"
>> +
>> +static void riscv_cps_init(Object *obj)
>> +{
>> + SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
>> + RISCVCPSState *s = RISCV_CPS(obj);
>> +
>> + /*
>> + * Cover entire address space as there do not seem to be any
>> + * constraints for the base address of CPC .
>> + */
>> + memory_region_init(&s->container, obj, "mips-cps-container",
>> UINT64_MAX);
>> + sysbus_init_mmio(sbd, &s->container);
>> +}
>> +
>> +static void main_cpu_reset(void *opaque)
>> +{
>> + CPUState *cs = opaque;
>> +
>> + cpu_reset(cs);
>> +}
>> +
>> +static void riscv_cps_realize(DeviceState *dev, Error **errp)
>> +{
>> + RISCVCPSState *s = RISCV_CPS(dev);
>> + RISCVCPU *cpu;
>> + int i;
>> +
>> + /* Validate num_vp */
>> + if (s->num_vp == 0) {
>> + error_setg(errp, "num-vp must be at least 1");
>> + return;
>> + }
>> + if (s->num_vp > MAX_HARTS) {
>> + error_setg(errp, "num-vp cannot exceed %d", MAX_HARTS);
>> + return;
>> + }
>> +
>> + /* Allocate CPU array */
>> + s->cpus = g_new0(CPUState *, s->num_vp);
>> +
>> + /* Set up cpu_index and mhartid for avaiable CPUs. */
>> + int harts_in_cluster = s->num_hart * s->num_core;
>> + int num_of_clusters = s->num_vp / harts_in_cluster;
>> + for (i = 0; i < s->num_vp; i++) {
>> + cpu = RISCV_CPU(object_new(s->cpu_type));
>> +
>> + /* All VPs are halted on reset. Leave powering up to CPC. */
>> + object_property_set_bool(OBJECT(cpu), "start-powered-off", true,
>> + &error_abort);
>> +
>> + if (!qdev_realize_and_unref(DEVICE(cpu), NULL, errp)) {
>> + return;
>> + }
>> +
>> + /* Store CPU in array */
>> + s->cpus[i] = CPU(cpu);
>> +
>> + /* Set up mhartid */
>> + int cluster_id = i / harts_in_cluster;
>> + int hart_id = (i % harts_in_cluster) % s->num_hart;
>> + int core_id = (i % harts_in_cluster) / s->num_hart;
>> + int mhartid = (cluster_id << MHARTID_CLUSTER_SHIFT) +
>> + (core_id << MHARTID_CORE_SHIFT) +
>> + (hart_id << MHARTID_HART_SHIFT);
>> + cpu->env.mhartid = mhartid;
>> + qemu_register_reset(main_cpu_reset, s->cpus[i]);
>> + }
>> +
>> + /* Cluster Power Controller */
>> + object_initialize_child(OBJECT(dev), "cpc", &s->cpc, TYPE_RISCV_CPC);
>> + object_property_set_uint(OBJECT(&s->cpc), "cluster-id", 0,
>> + &error_abort);
>> + object_property_set_uint(OBJECT(&s->cpc), "num-vp", s->num_vp,
>> + &error_abort);
>> + object_property_set_uint(OBJECT(&s->cpc), "num-hart", s->num_hart,
>> + &error_abort);
>> + object_property_set_uint(OBJECT(&s->cpc), "num-core", s->num_core,
>> + &error_abort);
>> +
>> + /* Pass CPUs to CPC using link properties */
>> + for (i = 0; i < s->num_vp; i++) {
>> + char *propname = g_strdup_printf("cpu[%d]", i);
>> + object_property_set_link(OBJECT(&s->cpc), propname,
>> + OBJECT(s->cpus[i]), &error_abort);
>> + g_free(propname);
>> + }
>> +
>> + if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpc), errp)) {
>> + return;
>> + }
>> +
>> + memory_region_add_subregion(&s->container, 0,
>> + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cpc),
>> 0));
>> +
>> + /* Global Configuration Registers */
>> + object_initialize_child(OBJECT(dev), "gcr", &s->gcr, TYPE_RISCV_GCR);
>> + object_property_set_uint(OBJECT(&s->gcr), "cluster-id", 0,
>> + &error_abort);
>> + object_property_set_uint(OBJECT(&s->gcr), "num-vp", s->num_vp,
>> + &error_abort);
>> + object_property_set_int(OBJECT(&s->gcr), "gcr-rev", 0xa00,
>> + &error_abort);
>> + object_property_set_int(OBJECT(&s->gcr), "gcr-base", s->gcr_base,
>> + &error_abort);
>> + object_property_set_link(OBJECT(&s->gcr), "cpc", OBJECT(&s->cpc.mr),
>> + &error_abort);
>> + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), errp)) {
>> + return;
>> + }
>> +
>> + memory_region_add_subregion(&s->container, s->gcr_base,
>> + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gcr),
>> 0));
>> +
>> + for (i = 0; i < num_of_clusters; i++) {
>> + uint64_t cm_base = GLOBAL_CM_BASE + (CM_SIZE * i);
> This causes a Coverity issue
>
> *** CID 1644076: Integer handling issues (OVERFLOW_BEFORE_WIDEN)
> /builds/qemu-project/qemu/hw/riscv/cps.c: 136 in
> riscv_cps_realize()
> 130 }
> 131
> 132 memory_region_add_subregion(&s->container, s->gcr_base,
> 133
> sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gcr), 0));
> 134
> 135 for (i = 0; i < num_of_clusters; i++) {
>>>> CID 1644076: Integer handling issues (OVERFLOW_BEFORE_WIDEN)
>>>> Potentially overflowing expression "524288 * i" with type "int" (32
>>>> bits, signed) is evaluated using 32-bit arithmetic, and then used in a
>>>> context that expects an expression of type "uint64_t" (64 bits, unsigned).
> 136 uint64_t cm_base = GLOBAL_CM_BASE + (CM_SIZE * i);
> 137 uint32_t hartid_base = i << MHARTID_CLUSTER_SHIFT;
> 138 s->aplic = riscv_aplic_create(cm_base + AIA_PLIC_M_OFFSET,
> 139 AIA_PLIC_M_SIZE,
> 140 hartid_base, /* hartid_base */
> 141 MAX_HARTS, /* num_harts */
>
>
> Can you send a patch to fix this issue and link to CID 1644076?
>
> Alistair
>
Hi Alistair,
Thanks for merging it.
Yes, I have just sent the two patches that fix those problems.
Best,
Djordje
>> + uint32_t hartid_base = i << MHARTID_CLUSTER_SHIFT;
>> + s->aplic = riscv_aplic_create(cm_base + AIA_PLIC_M_OFFSET,
>> + AIA_PLIC_M_SIZE,
>> + hartid_base, /* hartid_base */
>> + MAX_HARTS, /* num_harts */
>> + APLIC_NUM_SOURCES,
>> + APLIC_NUM_PRIO_BITS,
>> + false, true, NULL);
>> + riscv_aplic_create(cm_base + AIA_PLIC_S_OFFSET,
>> + AIA_PLIC_S_SIZE,
>> + hartid_base, /* hartid_base */
>> + MAX_HARTS, /* num_harts */
>> + APLIC_NUM_SOURCES,
>> + APLIC_NUM_PRIO_BITS,
>> + false, false, s->aplic);
>> + /* PLIC changes msi_nonbroken to ture. We revert the change. */
>> + msi_nonbroken = false;
>> + riscv_aclint_swi_create(cm_base + AIA_CLINT_OFFSET,
>> + hartid_base, MAX_HARTS, false);
>> + riscv_aclint_mtimer_create(cm_base + AIA_CLINT_OFFSET +
>> + RISCV_ACLINT_SWI_SIZE,
>> + RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
>> + hartid_base,
>> + MAX_HARTS,
>> + RISCV_ACLINT_DEFAULT_MTIMECMP,
>> + RISCV_ACLINT_DEFAULT_MTIME,
>> + RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ,
>> false);
>> + }
>> +}
>> +
>> +static const Property riscv_cps_properties[] = {
>> + DEFINE_PROP_UINT32("num-vp", RISCVCPSState, num_vp, 1),
>> + DEFINE_PROP_UINT32("num-hart", RISCVCPSState, num_hart, 1),
>> + DEFINE_PROP_UINT32("num-core", RISCVCPSState, num_core, 1),
>> + DEFINE_PROP_UINT64("gcr-base", RISCVCPSState, gcr_base, GCR_BASE_ADDR),
>> + DEFINE_PROP_STRING("cpu-type", RISCVCPSState, cpu_type),
>> +};
>> +
>> +static void riscv_cps_class_init(ObjectClass *klass, const void *data)
>> +{
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> + dc->realize = riscv_cps_realize;
>> + device_class_set_props(dc, riscv_cps_properties);
>> +}
>> +
>> +static const TypeInfo riscv_cps_info = {
>> + .name = TYPE_RISCV_CPS,
>> + .parent = TYPE_SYS_BUS_DEVICE,
>> + .instance_size = sizeof(RISCVCPSState),
>> + .instance_init = riscv_cps_init,
>> + .class_init = riscv_cps_class_init,
>> +};
>> +
>> +static void riscv_cps_register_types(void)
>> +{
>> + type_register_static(&riscv_cps_info);
>> +}
>> +
>> +type_init(riscv_cps_register_types)
>> diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
>> index 2a8d5b136c..9023b80087 100644
>> --- a/hw/riscv/meson.build
>> +++ b/hw/riscv/meson.build
>> @@ -15,4 +15,6 @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
>> riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true:
>> files('microblaze-v-generic.c'))
>> riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true:
>> files('xiangshan_kmh.c'))
>>
>> +riscv_ss.add(when: 'CONFIG_RISCV_MIPS_CPS', if_true: files('cps.c'))
>> +
>> hw_arch += {'riscv': riscv_ss}
>> diff --git a/include/hw/riscv/cps.h b/include/hw/riscv/cps.h
>> new file mode 100644
>> index 0000000000..f33fd7ac86
>> --- /dev/null
>> +++ b/include/hw/riscv/cps.h
>> @@ -0,0 +1,66 @@
>> +/*
>> + * Coherent Processing System emulation.
>> + *
>> + * Copyright (c) 2016 Imagination Technologies
>> + *
>> + * Copyright (c) 2025 MIPS
>> + *
>> + * SPDX-License-Identifier: GPL-2.0-or-later
>> + *
>> + */
>> +
>> +#ifndef RISCV_CPS_H
>> +#define RISCV_CPS_H
>> +
>> +#include "hw/core/sysbus.h"
>> +#include "hw/misc/riscv_cmgcr.h"
>> +#include "hw/misc/riscv_cpc.h"
>> +#include "target/riscv/cpu.h"
>> +#include "qom/object.h"
>> +
>> +#define TYPE_RISCV_CPS "riscv-cps"
>> +OBJECT_DECLARE_SIMPLE_TYPE(RISCVCPSState, RISCV_CPS)
>> +
>> +/* The model supports up to 64 harts. */
>> +#define MAX_HARTS 64
>> +
>> +/* The global CM base for the boston-aia model. */
>> +#define GLOBAL_CM_BASE 0x16100000
>> +/* The CM block is 512 KiB. */
>> +#define CM_SIZE (1 << 19)
>> +
>> +/*
>> + * The mhartid bits has cluster at bit 16, core at bit 4, and hart at
>> + * bit 0.
>> + */
>> +
>> +#define MHARTID_CLUSTER_SHIFT 16
>> +#define MHARTID_CORE_SHIFT 4
>> +#define MHARTID_HART_SHIFT 0
>> +
>> +#define APLIC_NUM_SOURCES 0x35 /* Arbitray maximum number of interrupts. */
>> +#define APLIC_NUM_PRIO_BITS 3
>> +#define AIA_PLIC_M_OFFSET 0x40000
>> +#define AIA_PLIC_M_SIZE 0x8000
>> +#define AIA_PLIC_S_OFFSET 0x60000
>> +#define AIA_PLIC_S_SIZE 0x8000
>> +#define AIA_CLINT_OFFSET 0x50000
>> +
>> +typedef struct RISCVCPSState {
>> + SysBusDevice parent_obj;
>> +
>> + uint32_t num_vp;
>> + uint32_t num_hart;
>> + uint32_t num_core;
>> + uint64_t gcr_base;
>> + char *cpu_type;
>> +
>> + MemoryRegion container;
>> + RISCVGCRState gcr;
>> + RISCVCPCState cpc;
>> +
>> + DeviceState *aplic;
>> + CPUState **cpus;
>> +} RISCVCPSState;
>> +
>> +#endif
>> --
>> 2.34.1