On 4/17/25 7:52 AM, Jim Shu wrote:
> riscv_worldguard_apply_cpu() could enable WG CPU extension and set WG
> callback to CPUs. It is used by machine code after realizing global WG
> device.
> > Signed-off-by: Jim Shu <jim....@sifive.com>
> ---
>   hw/misc/riscv_worldguard.c         | 87 ++++++++++++++++++++++++++++++
>   include/hw/misc/riscv_worldguard.h |  1 +
>   2 files changed, 88 insertions(+)
> > diff --git a/hw/misc/riscv_worldguard.c b/hw/misc/riscv_worldguard.c
> index b02bd28d02..1a910f4cf3 100644
> --- a/hw/misc/riscv_worldguard.c
> +++ b/hw/misc/riscv_worldguard.c
> @@ -92,6 +92,93 @@ uint32_t mem_attrs_to_wid(MemTxAttrs attrs)
>       }
>   }
> > +static void riscv_cpu_wg_reset(CPURISCVState *env)
> +{
> +    CPUState *cs = env_cpu(env);
> +    RISCVCPU *cpu = RISCV_CPU(cs);
> +    uint32_t mlwid, slwid, mwiddeleg;
> +    uint32_t trustedwid;
> +
> +    if (!riscv_cpu_cfg(env)->ext_smwg) {
> +        return;
> +    }
> +
> +    if (worldguard_config == NULL) {
> +        /*
> +         * Note: This reset is dummy now and WG CSRs will be reset again
> +         * after worldguard_config is realized.
> +         */
> +        return;
> +    }
> +
> +    trustedwid = worldguard_config->trustedwid;
> +    if (trustedwid == NO_TRUSTEDWID) {
> +        trustedwid = worldguard_config->nworlds - 1;
> +    }
> +
> +    /* Reset mlwid, slwid, mwiddeleg CSRs */
> +    if (worldguard_config->hw_bypass) {
> +        /* HW bypass mode */
> +        mlwid = trustedwid;
> +    } else {
> +        mlwid = 0;
> +    }
> +    slwid = 0;
> +    mwiddeleg = 0;
> +
> +    env->mlwid = mlwid;
> +    if (riscv_cpu_cfg(env)->ext_sswg) {
> +        env->slwid = slwid;
> +        env->mwiddeleg = mwiddeleg;
> +    }
> +
> +    /* Check mwid, mwidlist config */
> +    if (worldguard_config != NULL) {
> +        uint32_t valid_widlist = MAKE_64BIT_MASK(0, 
worldguard_config->nworlds);
> +
> +        /* CPU use default mwid / mwidlist config if not set */
> +        if (cpu->cfg.mwidlist == UINT32_MAX) {
> +            /* mwidlist contains all WIDs */
> +            cpu->cfg.mwidlist = valid_widlist;
> +        }
> +        if (cpu->cfg.mwid == UINT32_MAX) {
> +            cpu->cfg.mwid = trustedwid;
> +        }
> +
> +        /* Check if mwid/mwidlist HW config is valid in NWorld. */
> +        g_assert((cpu->cfg.mwidlist & ~valid_widlist) == 0);
> +        g_assert(cpu->cfg.mwid < worldguard_config->nworlds);
> +    }
> +}
> +
> +/*
> + * riscv_worldguard_apply_cpu - Enable WG extension of CPU
> + *
> + * Note: This API should be used after global WG device is created
> + * (riscv_worldguard_realize()).
> + */
> +void riscv_worldguard_apply_cpu(uint32_t hartid)
> +{
> +    /* WG global config should exist */
> +    g_assert(worldguard_config);

We usually add g_asserts() after the variable declarations.

> +
> +    CPUState *cpu = qemu_get_cpu(hartid);

arm_get_cpu() uses CPUState::cpu_index to obtain the corresponding CPUState 
pointer.

However, CPUState::cpu_index and the RISC-V HART index are not necessarily 
strictly
one-to-one (for instance, when the hartid base is non-zero or when hartids are
discontinuous).

Typically, we use arm_get_cpu() at the accelerators, rather than in hw/code.

A better approach is to use cpu_by_arch_id() instead of qemu_get_cpu(),
in RISC-V cpu_by_arch_id() uses the hartid.

e.g.

    CPUState *cpu = cpu_by_arch_id(hartid);


Thanks,

Chao

> +    RISCVCPU *rcpu = RISCV_CPU(cpu);
> +    CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
> +
> +    rcpu->cfg.ext_smwg = true;
> +    if (riscv_has_ext(env, RVS) && riscv_has_ext(env, RVU)) {
> +        rcpu->cfg.ext_sswg = true;
> +    }

riscv_has_ext() will segfault if env == NULL, and you're creating a code
path where this might happen:

> +    CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;

In fact, cpu == NULL will explode on you earlier via this macro:

> +    RISCVCPU *rcpu = RISCV_CPU(cpu);

You can either handle cpu == NULL with a clean exit before using 'cpu' to assign
stuff or g_assert(cpu != NULL) for a more rude exit. But with this code as is
you're gambling with segfaults.


Thanks,

Daniel


> +
> +    /* Set machine specific WorldGuard callback */
> +    env->wg_reset = riscv_cpu_wg_reset;
> +    env->wid_to_mem_attrs = wid_to_mem_attrs;
> +
> +    /* Reset WG CSRs in CPU */
> +    env->wg_reset(env);
> +}
> +
>   bool could_access_wgblocks(MemTxAttrs attrs, const char *wgblock)
>   {
>       uint32_t wid = mem_attrs_to_wid(attrs);
> diff --git a/include/hw/misc/riscv_worldguard.h 
b/include/hw/misc/riscv_worldguard.h
> index 8a533a0517..211a72e438 100644
> --- a/include/hw/misc/riscv_worldguard.h
> +++ b/include/hw/misc/riscv_worldguard.h
> @@ -48,6 +48,7 @@ extern struct RISCVWorldGuardState *worldguard_config;
> > DeviceState *riscv_worldguard_create(uint32_t nworlds, uint32_t trustedwid,
>                                        bool hw_bypass, bool tz_compat);
> +void riscv_worldguard_apply_cpu(uint32_t hartid);
> > uint32_t mem_attrs_to_wid(MemTxAttrs attrs);
>   bool could_access_wgblocks(MemTxAttrs attrs, const char *wgblock);



Reply via email to