On Wed, Jan 22, 2025 at 6:48 PM Ethan Chen via <qemu-devel@nongnu.org> wrote: > > This device determines the target IOPMP device for forwarding information > based on: > * Address: For parallel IOPMP devices > * Stage: For cascading IOPMP devices > > Signed-off-by: Ethan Chen <etha...@andestech.com> > --- > hw/misc/meson.build | 1 + > hw/misc/riscv_iopmp_dispatcher.c | 136 +++++++++++++++++++++++ > include/hw/misc/riscv_iopmp_dispatcher.h | 61 ++++++++++ > 3 files changed, 198 insertions(+) > create mode 100644 hw/misc/riscv_iopmp_dispatcher.c > create mode 100644 include/hw/misc/riscv_iopmp_dispatcher.h > > diff --git a/hw/misc/meson.build b/hw/misc/meson.build > index 88f2bb6b88..497f83637f 100644 > --- a/hw/misc/meson.build > +++ b/hw/misc/meson.build > @@ -35,6 +35,7 @@ system_ss.add(when: 'CONFIG_SIFIVE_E_AON', if_true: > files('sifive_e_aon.c')) > system_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c')) > system_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: > files('sifive_u_prci.c')) > specific_ss.add(when: 'CONFIG_RISCV_IOPMP', if_true: files('riscv_iopmp.c')) > +specific_ss.add(when: 'CONFIG_RISCV_IOPMP', if_true: > files('riscv_iopmp_dispatcher.c')) > > subdir('macio') > > diff --git a/hw/misc/riscv_iopmp_dispatcher.c > b/hw/misc/riscv_iopmp_dispatcher.c > new file mode 100644 > index 0000000000..4086e9c82b > --- /dev/null > +++ b/hw/misc/riscv_iopmp_dispatcher.c > @@ -0,0 +1,136 @@ > +/* > + * QEMU RISC-V IOPMP dispatcher > + * > + * Receives transaction information from the requestor and forwards it to the > + * corresponding IOPMP device. > + * > + * Copyright (c) 2023-2025 Andes Tech. Corp. > + * > + * SPDX-License-Identifier: GPL-2.0-or-later > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2 or later, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + * > + * You should have received a copy of the GNU General Public License along > with > + * this program. If not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "qemu/osdep.h" > +#include "qemu/log.h" > +#include "qapi/error.h" > +#include "trace.h" > +#include "exec/exec-all.h" > +#include "exec/address-spaces.h" > +#include "hw/qdev-properties.h" > +#include "hw/sysbus.h" > +#include "hw/misc/riscv_iopmp_dispatcher.h" > +#include "memory.h" > +#include "hw/irq.h" > +#include "hw/misc/riscv_iopmp_txn_info.h" > + > +static void riscv_iopmp_dispatcher_realize(DeviceState *dev, Error **errp) > +{ > + int i; > + RISCVIOPMPDispState *s = RISCV_IOPMP_DISP(dev); > + > + s->SinkMemMap = g_new(SinkMemMapEntry *, s->stage_num); > + for (i = 0; i < s->stage_num; i++) { > + s->SinkMemMap[i] = g_new(SinkMemMapEntry, s->target_num); > + } > + > + object_initialize_child(OBJECT(s), "iopmp_dispatcher_txn_info", > + &s->txn_info_sink, > + TYPE_RISCV_IOPMP_DISP_SS); > +} > + > +static const Property iopmp_dispatcher_properties[] = { > + DEFINE_PROP_UINT32("stage-num", RISCVIOPMPDispState, stage_num, 2), > + DEFINE_PROP_UINT32("target-num", RISCVIOPMPDispState, target_num, 10), > +}; > + > +static void riscv_iopmp_dispatcher_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + device_class_set_props(dc, iopmp_dispatcher_properties); > + dc->realize = riscv_iopmp_dispatcher_realize; > +} > + > +static const TypeInfo riscv_iopmp_dispatcher_info = { > + .name = TYPE_RISCV_IOPMP_DISP, > + .parent = TYPE_DEVICE, > + .instance_size = sizeof(RISCVIOPMPDispState), > + .class_init = riscv_iopmp_dispatcher_class_init, > +}; > + > +static size_t dispatcher_txn_info_push(StreamSink *txn_info_sink, > + unsigned char *buf, > + size_t len, bool eop) > +{ > + uint64_t addr; > + uint32_t stage; > + int i, j; > + riscv_iopmp_disp_ss *ss = > + RISCV_IOPMP_DISP_SS(txn_info_sink); > + RISCVIOPMPDispState *s = RISCV_IOPMP_DISP(container_of(ss, > + RISCVIOPMPDispState, txn_info_sink)); > + riscv_iopmp_txn_info signal; > + memcpy(&signal, buf, len);
Shouldn't the `len` be verified before this? Also, instead of copying if you can cast the `buf` pointer to a `riscv_iopmp_txn_info` pointer Alistair > + addr = signal.start_addr; > + stage = signal.stage; > + for (i = stage; i < s->stage_num; i++) { > + for (j = 0; j < s->target_num; j++) { > + if (s->SinkMemMap[i][j].map.base <= addr && > + addr < s->SinkMemMap[i][j].map.base > + + s->SinkMemMap[i][j].map.size) { > + return stream_push(s->SinkMemMap[i][j].sink, buf, len, > eop); > + } > + } > + } > + /* Always pass if target is not protected by IOPMP*/ > + return 1; > +} > + > +static void riscv_iopmp_disp_ss_class_init( > + ObjectClass *klass, void *data) > +{ > + StreamSinkClass *ssc = STREAM_SINK_CLASS(klass); > + ssc->push = dispatcher_txn_info_push; > +} > + > +static const TypeInfo riscv_iopmp_disp_ss_info = { > + .name = TYPE_RISCV_IOPMP_DISP_SS, > + .parent = TYPE_OBJECT, > + .instance_size = sizeof(riscv_iopmp_disp_ss), > + .class_init = riscv_iopmp_disp_ss_class_init, > + .interfaces = (InterfaceInfo[]) { > + { TYPE_STREAM_SINK }, > + { } > + }, > +}; > + > +void iopmp_dispatcher_add_target(DeviceState *dev, StreamSink *sink, > + uint64_t base, uint64_t size, uint32_t stage, uint32_t id) > +{ > + RISCVIOPMPDispState *s = RISCV_IOPMP_DISP(dev); > + if (stage < s->stage_num && id < s->target_num) { > + s->SinkMemMap[stage][id].map.base = base; > + s->SinkMemMap[stage][id].map.size = size; > + s->SinkMemMap[stage][id].sink = sink; > + } > +} > + > +static void > +iopmp_dispatcher_register_types(void) > +{ > + type_register_static(&riscv_iopmp_dispatcher_info); > + type_register_static(&riscv_iopmp_disp_ss_info); > +} > + > +type_init(iopmp_dispatcher_register_types); > + > diff --git a/include/hw/misc/riscv_iopmp_dispatcher.h > b/include/hw/misc/riscv_iopmp_dispatcher.h > new file mode 100644 > index 0000000000..bbaa76507b > --- /dev/null > +++ b/include/hw/misc/riscv_iopmp_dispatcher.h > @@ -0,0 +1,61 @@ > +/* > + * QEMU RISC-V IOPMP dispatcher > + * > + * Receives transaction information from the requestor and forwards it to the > + * corresponding IOPMP device. > + * > + * Copyright (c) 2023-2024 Andes Tech. Corp. > + * > + * SPDX-License-Identifier: GPL-2.0-or-later > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2 or later, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + * > + * You should have received a copy of the GNU General Public License along > with > + * this program. If not, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef RISCV_IOPMP_DISPATCHER_H > +#define RISCV_IOPMP_DISPATCHER_H > + > +#include "hw/sysbus.h" > +#include "qemu/typedefs.h" > +#include "memory.h" > +#include "hw/stream.h" > +#include "hw/misc/riscv_iopmp_txn_info.h" > +#include "exec/hwaddr.h" > + > +#define TYPE_RISCV_IOPMP_DISP "riscv-iopmp-dispatcher" > +OBJECT_DECLARE_SIMPLE_TYPE(RISCVIOPMPDispState, RISCV_IOPMP_DISP) > + > +#define TYPE_RISCV_IOPMP_DISP_SS "riscv-iopmp-dispatcher-streamsink" > +OBJECT_DECLARE_SIMPLE_TYPE(riscv_iopmp_disp_ss, RISCV_IOPMP_DISP_SS) > + > +typedef struct riscv_iopmp_disp_ss { > + Object parent; > +} riscv_iopmp_disp_ss; > + > +typedef struct SinkMemMapEntry { > + StreamSink *sink; > + MemMapEntry map; > +} SinkMemMapEntry; > + > +typedef struct RISCVIOPMPDispState { > + SysBusDevice parent_obj; > + riscv_iopmp_disp_ss txn_info_sink; > + SinkMemMapEntry **SinkMemMap; > + /* The maximum number of cascading stages of IOPMP */ > + uint32_t stage_num; > + /* The maximum number of parallel IOPMP devices within a single stage. */ > + uint32_t target_num; > +} RISCVIOPMPDispState; > + > +void iopmp_dispatcher_add_target(DeviceState *dev, StreamSink *sink, > + uint64_t base, uint64_t size, uint32_t stage, uint32_t id); > +#endif > -- > 2.34.1 > >