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

Reply via email to