On Wed, Jan 14, 2026 at 02:46:37PM +0800, Nicholas Piggin wrote:
> The check_itrigger_priv() did not check privilege bits properly. Move
> all priv checks into functions and have the icount check follow the same
> form as the others.
> 
> Signed-off-by: Nicholas Piggin <[email protected]>
> ---
>  target/riscv/debug.c | 82 ++++++++++++++++++++------------------------
>  1 file changed, 37 insertions(+), 45 deletions(-)
> 
> diff --git a/target/riscv/debug.c b/target/riscv/debug.c
> index c92bd9860e..2effbb49af 100644
> --- a/target/riscv/debug.c
> +++ b/target/riscv/debug.c
> @@ -306,48 +306,50 @@ static void do_trigger_action(CPURISCVState *env, 
> target_ulong trigger_index)
>   * Check the privilege level of specific trigger matches CPU's current 
> privilege
>   * level.
>   */
> +static bool type2_priv_match(CPURISCVState *env, target_ulong tdata1)
> +{
> +    /* type 2 trigger cannot be fired in VU/VS mode */
> +    if (env->virt_enabled) {
> +        return false;
> +    }
> +    /* check U/S/M bit against current privilege level */
> +    return (((tdata1 >> 3) & 0b1011) & BIT(env->priv));
> +}
> +
> +static bool type6_priv_match(CPURISCVState *env, target_ulong tdata1)
> +{
> +    if (env->virt_enabled) {
> +        /* check VU/VS bit against current privilege level */
> +        return (((tdata1 >> 23) & 0b11) & BIT(env->priv));
> +    } else {
> +        /* check U/S/M bit against current privilege level */
> +        return (((tdata1 >> 3) & 0b1011) & BIT(env->priv));
> +    }
> +}
The new logic looks correct to me, but now it uses open-coded shifts
and masks to check the privilege bits.

Since we already have these bits defined in debug.h, like `TYPE2_U/S/M`,
`TYPE6_VU/VS/U/S/M` and `ITRIGGER_VU/VS/U/S/M`, I think it would be
better to use those masks through a small helper instead of spelling
out `>> 3`, `>> 6`, `>> 23` and `0b1011` here.

That would make the code easier to read and maintain later.

like:

```
static bool trigger_priv_bit_match(target_ulong tdata1,
                                   target_ulong u_mask,
                                   target_ulong s_mask,
                                   target_ulong m_mask,
                                   target_ulong priv)
{
    switch (priv) {
    case PRV_U:
        return (tdata1 & u_mask) != 0;
    case PRV_S:
        return (tdata1 & s_mask) != 0;
    case PRV_M:
        return (tdata1 & m_mask) != 0;
    default:
        g_assert_not_reached();
    }
}

static bool trigger_vpriv_bit_match(target_ulong tdata1,
                                    target_ulong vu_mask,
                                    target_ulong vs_mask,
                                    target_ulong priv)
{
    switch (priv) {
    case PRV_U:
        return (tdata1 & vu_mask) != 0;
    case PRV_S:
        return (tdata1 & vs_mask) != 0;
    default:
        return false;
    }
}
```

So we can call it this way:

```
static bool type2_priv_match(CPURISCVState *env, target_ulong tdata1)
{
    /* type 2 trigger cannot be fired in VU/VS mode */
    if (env->virt_enabled) {
        return false;
    }

    return trigger_priv_bit_match(tdata1, TYPE2_U, TYPE2_S, TYPE2_M,
                                  env->priv);
}

static bool type6_priv_match(CPURISCVState *env, target_ulong tdata1)
{
    if (env->virt_enabled) {
        return trigger_vpriv_bit_match(tdata1, TYPE6_VU, TYPE6_VS,
                                       env->priv);
    }

    return trigger_priv_bit_match(tdata1, TYPE6_U, TYPE6_S, TYPE6_M,
                                  env->priv);
}

static bool icount_priv_match(CPURISCVState *env, target_ulong tdata1)
{
    if (env->virt_enabled) {
        return trigger_vpriv_bit_match(tdata1, ITRIGGER_VU, ITRIGGER_VS,
                                       env->priv);
    }

    return trigger_priv_bit_match(tdata1, ITRIGGER_U, ITRIGGER_S, ITRIGGER_M,
                                  env->priv);
}
```

And I don't mean going back to `get_field(mask) == env->priv`; that pattern
is easy to get wrong for `PRV_U == 0`. The helper should just test the mask
selected by the current privilege.

Thanks,
Chao
> +
> +static bool icount_priv_match(CPURISCVState *env, target_ulong tdata1)
> +{
> +    if (env->virt_enabled) {
> +        /* check VU/VS bit against current privilege level */
> +        return (((tdata1 >> 25) & 0b11) & BIT(env->priv));
> +    } else {
> +        /* check U/S/M bit against current privilege level */
> +        return (((tdata1 >> 6) & 0b1011) & BIT(env->priv));
> +    }
> +}
> +
>  static bool trigger_priv_match(CPURISCVState *env, trigger_type_t type,
>                                 int trigger_index)
>  {
> -    target_ulong ctrl = env->tdata1[trigger_index];
> +    target_ulong tdata1 = env->tdata1[trigger_index];
>  
>      switch (type) {
>      case TRIGGER_TYPE_AD_MATCH:
> -        /* type 2 trigger cannot be fired in VU/VS mode */
> -        if (env->virt_enabled) {
> -            return false;
> -        }
> -        /* check U/S/M bit against current privilege level */
> -        if ((ctrl >> 3) & BIT(env->priv)) {
> -            return true;
> -        }
> -        break;
> +        return type2_priv_match(env, tdata1);
>      case TRIGGER_TYPE_AD_MATCH6:
> -        if (env->virt_enabled) {
> -            /* check VU/VS bit against current privilege level */
> -            if ((ctrl >> 23) & BIT(env->priv)) {
> -                return true;
> -            }
> -        } else {
> -            /* check U/S/M bit against current privilege level */
> -            if ((ctrl >> 3) & BIT(env->priv)) {
> -                return true;
> -            }
> -        }
> -        break;
> +        return type6_priv_match(env, tdata1);
>      case TRIGGER_TYPE_INST_CNT:
> -        if (env->virt_enabled) {
> -            /* check VU/VS bit against current privilege level */
> -            if ((ctrl >> 25) & BIT(env->priv)) {
> -                return true;
> -            }
> -        } else {
> -            /* check U/S/M bit against current privilege level */
> -            if ((ctrl >> 6) & BIT(env->priv)) {
> -                return true;
> -            }
> -        }
> -        break;
> +        return icount_priv_match(env, tdata1);
>      case TRIGGER_TYPE_INT:
>      case TRIGGER_TYPE_EXCP:
>      case TRIGGER_TYPE_EXT_SRC:
> @@ -665,17 +667,7 @@ itrigger_set_count(CPURISCVState *env, int index, int 
> value)
>  
>  static bool check_itrigger_priv(CPURISCVState *env, int index)
>  {
> -    target_ulong tdata1 = env->tdata1[index];
> -    if (env->virt_enabled) {
> -        /* check VU/VS bit against current privilege level */
> -        return (get_field(tdata1, ITRIGGER_VS) == env->priv) ||
> -               (get_field(tdata1, ITRIGGER_VU) == env->priv);
> -    } else {
> -        /* check U/S/M bit against current privilege level */
> -        return (get_field(tdata1, ITRIGGER_M) == env->priv) ||
> -               (get_field(tdata1, ITRIGGER_S) == env->priv) ||
> -               (get_field(tdata1, ITRIGGER_U) == env->priv);
> -    }
> +    return icount_priv_match(env, index);
>  }
>  
>  bool riscv_itrigger_enabled(CPURISCVState *env)
> -- 
> 2.51.0
> 
> 

Reply via email to