diff mbox series

[v2,3/6] target/riscv: Add support for Control Transfer Records extension CSRs.

Message ID 20240619152708.135991-4-rkanwal@rivosinc.com (mailing list archive)
State New, archived
Headers show
Series target/riscv: Add support for Control Transfer Records Ext. | expand

Commit Message

Rajnesh Kanwal June 19, 2024, 3:27 p.m. UTC
This commit adds support for [m|s|vs]ctrcontrol, sctrstatus and
sctrdepth CSRs handling.

Signed-off-by: Rajnesh Kanwal <rkanwal@rivosinc.com>
---
 target/riscv/cpu.h     |   5 ++
 target/riscv/cpu_cfg.h |   2 +
 target/riscv/csr.c     | 128 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 135 insertions(+)

Comments

Jason Chien June 25, 2024, 8:28 a.m. UTC | #1
Hi Rajnesh,

On 2024/6/19 下午 11:27, Rajnesh Kanwal wrote:
> This commit adds support for [m|s|vs]ctrcontrol, sctrstatus and
> sctrdepth CSRs handling.
>
> Signed-off-by: Rajnesh Kanwal <rkanwal@rivosinc.com>
> ---
>   target/riscv/cpu.h     |   5 ++
>   target/riscv/cpu_cfg.h |   2 +
>   target/riscv/csr.c     | 128 +++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 135 insertions(+)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index a185e2d494..3d4d5172b8 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -263,6 +263,11 @@ struct CPUArchState {
>       target_ulong mcause;
>       target_ulong mtval;  /* since: priv-1.10.0 */
>   
> +    uint64_t mctrctl;
> +    uint32_t sctrdepth;
> +    uint32_t sctrstatus;
> +    uint64_t vsctrctl;
> +
>       /* Machine and Supervisor interrupt priorities */
>       uint8_t miprio[64];
>       uint8_t siprio[64];
> diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
> index d9354dc80a..d329a65811 100644
> --- a/target/riscv/cpu_cfg.h
> +++ b/target/riscv/cpu_cfg.h
> @@ -123,6 +123,8 @@ struct RISCVCPUConfig {
>       bool ext_zvfhmin;
>       bool ext_smaia;
>       bool ext_ssaia;
> +    bool ext_smctr;
> +    bool ext_ssctr;
>       bool ext_sscofpmf;
>       bool ext_smepmp;
>       bool rvv_ta_all_1s;
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 2f92e4b717..0b5bf4d050 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -621,6 +621,48 @@ static RISCVException pointer_masking(CPURISCVState *env, int csrno)
>       return RISCV_EXCP_ILLEGAL_INST;
>   }
>   
> +/*
> + * M-mode:
> + * Without ext_smctr raise illegal inst excep.
> + * Otherwise everything is accessible to m-mode.
> + *
> + * S-mode:
> + * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
> + * Otherwise everything other than mctrctl is accessible.
> + *
> + * VS-mode:
> + * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
> + * Without hstateen.ctr raise virtual illegal inst excep.
> + * Otherwise allow sctrctl (vsctrctl), sctrstatus, 0x200-0x2ff entry range.
> + * Always raise illegal instruction exception for sctrdepth.
> + */
> +static RISCVException ctr_mmode(CPURISCVState *env, int csrno)
> +{
> +    /* Check if smctr-ext is present */
> +    if (riscv_cpu_cfg(env)->ext_smctr) {
> +        return RISCV_EXCP_NONE;
> +    }
> +
> +    return RISCV_EXCP_ILLEGAL_INST;
> +}
> +
> +static RISCVException ctr_smode(CPURISCVState *env, int csrno)
> +{
> +    const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
> +
> +    if (!cfg->ext_smctr && !cfg->ext_ssctr) {
> +        return RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    RISCVException ret = smstateen_acc_ok(env, 0, SMSTATEEN0_CTR);
> +    if (ret == RISCV_EXCP_NONE && csrno == CSR_SCTRDEPTH &&
> +        env->virt_enabled) {
> +        return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +    }
> +
> +    return ret;
> +}
> +
>   static RISCVException aia_hmode(CPURISCVState *env, int csrno)
>   {
>       int ret;
> @@ -3835,6 +3877,86 @@ static RISCVException write_satp(CPURISCVState *env, int csrno,
>       return RISCV_EXCP_NONE;
>   }
>   
> +static RISCVException rmw_sctrdepth(CPURISCVState *env, int csrno,
> +                                    target_ulong *ret_val,
> +                                    target_ulong new_val, target_ulong wr_mask)
> +{
> +    uint64_t mask = wr_mask & SCTRDEPTH_MASK;
> +
> +    if (ret_val) {
> +        *ret_val = env->sctrdepth;
> +    }
> +
> +    env->sctrdepth = (env->sctrdepth & ~mask) | (new_val & mask);
> +
> +    /* Correct depth. */
> +    if (wr_mask & SCTRDEPTH_MASK) {

We can use the variable "mask" here.

if (mask) {}

> +        uint64_t depth = get_field(env->sctrdepth, SCTRDEPTH_MASK);
> +
> +        if (depth > SCTRDEPTH_MAX) {
> +            depth = SCTRDEPTH_MAX;
> +            env->sctrdepth = set_field(env->sctrdepth, SCTRDEPTH_MASK, depth);
> +        }
> +
> +        /* Update sctrstatus.WRPTR with a legal value */
> +        depth = 16 << depth;
> +        env->sctrstatus =
> +            env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
> +    }
> +
> +    return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException rmw_sctrstatus(CPURISCVState *env, int csrno,
> +                                     target_ulong *ret_val,
> +                                     target_ulong new_val, target_ulong wr_mask)
> +{
> +    uint32_t depth = 16 << get_field(env->sctrdepth, SCTRDEPTH_MASK);
> +    uint32_t mask = wr_mask & SCTRSTATUS_MASK;
> +
> +    if (ret_val) {
> +        *ret_val = env->sctrstatus;
> +    }
> +
> +    env->sctrstatus = (env->sctrstatus & ~mask) | (new_val & mask);
> +
> +    /* Update sctrstatus.WRPTR with a legal value */
> +    env->sctrstatus = env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
> +
> +    return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException rmw_xctrctl(CPURISCVState *env, int csrno,
> +                                    target_ulong *ret_val,
> +                                    target_ulong new_val, target_ulong wr_mask)
> +{
> +    uint64_t csr_mask, mask = wr_mask;
> +    uint64_t *ctl_ptr = &env->mctrctl;
> +
> +    if (csrno == CSR_MCTRCTL) {
> +        csr_mask = MCTRCTL_MASK;
> +    } else if (csrno == CSR_SCTRCTL && !env->virt_enabled) {
> +        csr_mask = SCTRCTL_MASK;
> +    } else {
> +        /*
> +         * This is for csrno == CSR_SCTRCTL and env->virt_enabled == true
> +         * or csrno == CSR_VSCTRCTL.
> +         */
> +        csr_mask = VSCTRCTL_MASK;
> +        ctl_ptr = &env->vsctrctl;
> +    }
> +
> +    mask &= csr_mask;
> +
> +    if (ret_val) {
> +        *ret_val = *ctl_ptr & csr_mask;
> +    }
> +
> +    *ctl_ptr = (*ctl_ptr & ~mask) | (new_val & mask);
> +
> +    return RISCV_EXCP_NONE;
> +}
> +
>   static RISCVException read_vstopi(CPURISCVState *env, int csrno,
>                                     target_ulong *val)
>   {
> @@ -5771,6 +5893,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>       [CSR_SPMBASE] =    { "spmbase", pointer_masking, read_spmbase,
>                            write_spmbase                                      },
>   
> +    [CSR_MCTRCTL]    = { "mctrctl",    ctr_mmode,  NULL, NULL, rmw_xctrctl },
> +    [CSR_SCTRCTL]    = { "sctrctl",    ctr_smode,  NULL, NULL, rmw_xctrctl },
> +    [CSR_VSCTRCTL]   = { "vsctrctl",   ctr_smode,  NULL, NULL, rmw_xctrctl },
> +    [CSR_SCTRDEPTH]  = { "sctrdepth",  ctr_smode,  NULL, NULL, rmw_sctrdepth },
> +    [CSR_SCTRSTATUS] = { "sctrstatus", ctr_smode,  NULL, NULL, rmw_sctrstatus },
Would you mind aligning the right curly bracket like other CSR entries?
> +
>       /* Performance Counters */
>       [CSR_HPMCOUNTER3]    = { "hpmcounter3",    ctr,    read_hpmcounter },
>       [CSR_HPMCOUNTER4]    = { "hpmcounter4",    ctr,    read_hpmcounter },
Frank Chang Aug. 27, 2024, 9:28 a.m. UTC | #2
Rajnesh Kanwal <rkanwal@rivosinc.com> 於 2024年6月19日 週三 下午11:27寫道:
>
> This commit adds support for [m|s|vs]ctrcontrol, sctrstatus and
> sctrdepth CSRs handling.
>
> Signed-off-by: Rajnesh Kanwal <rkanwal@rivosinc.com>
> ---
>  target/riscv/cpu.h     |   5 ++
>  target/riscv/cpu_cfg.h |   2 +
>  target/riscv/csr.c     | 128 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 135 insertions(+)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index a185e2d494..3d4d5172b8 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -263,6 +263,11 @@ struct CPUArchState {
>      target_ulong mcause;
>      target_ulong mtval;  /* since: priv-1.10.0 */
>
> +    uint64_t mctrctl;
> +    uint32_t sctrdepth;
> +    uint32_t sctrstatus;
> +    uint64_t vsctrctl;
> +
>      /* Machine and Supervisor interrupt priorities */
>      uint8_t miprio[64];
>      uint8_t siprio[64];
> diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
> index d9354dc80a..d329a65811 100644
> --- a/target/riscv/cpu_cfg.h
> +++ b/target/riscv/cpu_cfg.h
> @@ -123,6 +123,8 @@ struct RISCVCPUConfig {
>      bool ext_zvfhmin;
>      bool ext_smaia;
>      bool ext_ssaia;
> +    bool ext_smctr;
> +    bool ext_ssctr;

Base on: https://github.com/riscv/riscv-control-transfer-records/pull/29
Smctr and Ssctr depend on both S-mode and Sscsrind.
We should add the implied rules for Smctr and Ssctr.

Regards,
Frank Chang


>      bool ext_sscofpmf;
>      bool ext_smepmp;
>      bool rvv_ta_all_1s;
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 2f92e4b717..0b5bf4d050 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -621,6 +621,48 @@ static RISCVException pointer_masking(CPURISCVState *env, int csrno)
>      return RISCV_EXCP_ILLEGAL_INST;
>  }
>
> +/*
> + * M-mode:
> + * Without ext_smctr raise illegal inst excep.
> + * Otherwise everything is accessible to m-mode.
> + *
> + * S-mode:
> + * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
> + * Otherwise everything other than mctrctl is accessible.
> + *
> + * VS-mode:
> + * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
> + * Without hstateen.ctr raise virtual illegal inst excep.
> + * Otherwise allow sctrctl (vsctrctl), sctrstatus, 0x200-0x2ff entry range.
> + * Always raise illegal instruction exception for sctrdepth.
> + */
> +static RISCVException ctr_mmode(CPURISCVState *env, int csrno)
> +{
> +    /* Check if smctr-ext is present */
> +    if (riscv_cpu_cfg(env)->ext_smctr) {
> +        return RISCV_EXCP_NONE;
> +    }
> +
> +    return RISCV_EXCP_ILLEGAL_INST;
> +}
> +
> +static RISCVException ctr_smode(CPURISCVState *env, int csrno)
> +{
> +    const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
> +
> +    if (!cfg->ext_smctr && !cfg->ext_ssctr) {
> +        return RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    RISCVException ret = smstateen_acc_ok(env, 0, SMSTATEEN0_CTR);
> +    if (ret == RISCV_EXCP_NONE && csrno == CSR_SCTRDEPTH &&
> +        env->virt_enabled) {
> +        return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +    }
> +
> +    return ret;
> +}
> +
>  static RISCVException aia_hmode(CPURISCVState *env, int csrno)
>  {
>      int ret;
> @@ -3835,6 +3877,86 @@ static RISCVException write_satp(CPURISCVState *env, int csrno,
>      return RISCV_EXCP_NONE;
>  }
>
> +static RISCVException rmw_sctrdepth(CPURISCVState *env, int csrno,
> +                                    target_ulong *ret_val,
> +                                    target_ulong new_val, target_ulong wr_mask)
> +{
> +    uint64_t mask = wr_mask & SCTRDEPTH_MASK;
> +
> +    if (ret_val) {
> +        *ret_val = env->sctrdepth;
> +    }
> +
> +    env->sctrdepth = (env->sctrdepth & ~mask) | (new_val & mask);
> +
> +    /* Correct depth. */
> +    if (wr_mask & SCTRDEPTH_MASK) {
> +        uint64_t depth = get_field(env->sctrdepth, SCTRDEPTH_MASK);
> +
> +        if (depth > SCTRDEPTH_MAX) {
> +            depth = SCTRDEPTH_MAX;
> +            env->sctrdepth = set_field(env->sctrdepth, SCTRDEPTH_MASK, depth);
> +        }
> +
> +        /* Update sctrstatus.WRPTR with a legal value */
> +        depth = 16 << depth;
> +        env->sctrstatus =
> +            env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
> +    }
> +
> +    return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException rmw_sctrstatus(CPURISCVState *env, int csrno,
> +                                     target_ulong *ret_val,
> +                                     target_ulong new_val, target_ulong wr_mask)
> +{
> +    uint32_t depth = 16 << get_field(env->sctrdepth, SCTRDEPTH_MASK);
> +    uint32_t mask = wr_mask & SCTRSTATUS_MASK;
> +
> +    if (ret_val) {
> +        *ret_val = env->sctrstatus;
> +    }
> +
> +    env->sctrstatus = (env->sctrstatus & ~mask) | (new_val & mask);
> +
> +    /* Update sctrstatus.WRPTR with a legal value */
> +    env->sctrstatus = env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
> +
> +    return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException rmw_xctrctl(CPURISCVState *env, int csrno,
> +                                    target_ulong *ret_val,
> +                                    target_ulong new_val, target_ulong wr_mask)
> +{
> +    uint64_t csr_mask, mask = wr_mask;
> +    uint64_t *ctl_ptr = &env->mctrctl;
> +
> +    if (csrno == CSR_MCTRCTL) {
> +        csr_mask = MCTRCTL_MASK;
> +    } else if (csrno == CSR_SCTRCTL && !env->virt_enabled) {
> +        csr_mask = SCTRCTL_MASK;
> +    } else {
> +        /*
> +         * This is for csrno == CSR_SCTRCTL and env->virt_enabled == true
> +         * or csrno == CSR_VSCTRCTL.
> +         */
> +        csr_mask = VSCTRCTL_MASK;
> +        ctl_ptr = &env->vsctrctl;
> +    }
> +
> +    mask &= csr_mask;
> +
> +    if (ret_val) {
> +        *ret_val = *ctl_ptr & csr_mask;
> +    }
> +
> +    *ctl_ptr = (*ctl_ptr & ~mask) | (new_val & mask);
> +
> +    return RISCV_EXCP_NONE;
> +}
> +
>  static RISCVException read_vstopi(CPURISCVState *env, int csrno,
>                                    target_ulong *val)
>  {
> @@ -5771,6 +5893,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      [CSR_SPMBASE] =    { "spmbase", pointer_masking, read_spmbase,
>                           write_spmbase                                      },
>
> +    [CSR_MCTRCTL]    = { "mctrctl",    ctr_mmode,  NULL, NULL, rmw_xctrctl },
> +    [CSR_SCTRCTL]    = { "sctrctl",    ctr_smode,  NULL, NULL, rmw_xctrctl },
> +    [CSR_VSCTRCTL]   = { "vsctrctl",   ctr_smode,  NULL, NULL, rmw_xctrctl },
> +    [CSR_SCTRDEPTH]  = { "sctrdepth",  ctr_smode,  NULL, NULL, rmw_sctrdepth },
> +    [CSR_SCTRSTATUS] = { "sctrstatus", ctr_smode,  NULL, NULL, rmw_sctrstatus },
> +
>      /* Performance Counters */
>      [CSR_HPMCOUNTER3]    = { "hpmcounter3",    ctr,    read_hpmcounter },
>      [CSR_HPMCOUNTER4]    = { "hpmcounter4",    ctr,    read_hpmcounter },
> --
> 2.34.1
>
>
Rajnesh Kanwal Oct. 17, 2024, 11:18 a.m. UTC | #3
On Tue, Aug 27, 2024 at 10:28 AM Frank Chang <frank.chang@sifive.com> wrote:
>
> Rajnesh Kanwal <rkanwal@rivosinc.com> 於 2024年6月19日 週三 下午11:27寫道:
> >
> > This commit adds support for [m|s|vs]ctrcontrol, sctrstatus and
> > sctrdepth CSRs handling.
> >
> > Signed-off-by: Rajnesh Kanwal <rkanwal@rivosinc.com>
> > ---
> >  target/riscv/cpu.h     |   5 ++
> >  target/riscv/cpu_cfg.h |   2 +
> >  target/riscv/csr.c     | 128 +++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 135 insertions(+)
> >
> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > index a185e2d494..3d4d5172b8 100644
> > --- a/target/riscv/cpu.h
> > +++ b/target/riscv/cpu.h
> > @@ -263,6 +263,11 @@ struct CPUArchState {
> >      target_ulong mcause;
> >      target_ulong mtval;  /* since: priv-1.10.0 */
> >
> > +    uint64_t mctrctl;
> > +    uint32_t sctrdepth;
> > +    uint32_t sctrstatus;
> > +    uint64_t vsctrctl;
> > +
> >      /* Machine and Supervisor interrupt priorities */
> >      uint8_t miprio[64];
> >      uint8_t siprio[64];
> > diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
> > index d9354dc80a..d329a65811 100644
> > --- a/target/riscv/cpu_cfg.h
> > +++ b/target/riscv/cpu_cfg.h
> > @@ -123,6 +123,8 @@ struct RISCVCPUConfig {
> >      bool ext_zvfhmin;
> >      bool ext_smaia;
> >      bool ext_ssaia;
> > +    bool ext_smctr;
> > +    bool ext_ssctr;
>
> Base on: https://github.com/riscv/riscv-control-transfer-records/pull/29
> Smctr and Ssctr depend on both S-mode and Sscsrind.
> We should add the implied rules for Smctr and Ssctr.
>
> Regards,
> Frank Chang

Hi Frank,

Are you referring to the checks in riscv_cpu_validate_set_extensions()?
These checks are already present in the last patch.

https://lore.kernel.org/qemu-riscv/20240619152708.135991-7-rkanwal@rivosinc.com/


>
>
> >      bool ext_sscofpmf;
> >      bool ext_smepmp;
> >      bool rvv_ta_all_1s;
> > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> > index 2f92e4b717..0b5bf4d050 100644
> > --- a/target/riscv/csr.c
> > +++ b/target/riscv/csr.c
> > @@ -621,6 +621,48 @@ static RISCVException pointer_masking(CPURISCVState *env, int csrno)
> >      return RISCV_EXCP_ILLEGAL_INST;
> >  }
> >
> > +/*
> > + * M-mode:
> > + * Without ext_smctr raise illegal inst excep.
> > + * Otherwise everything is accessible to m-mode.
> > + *
> > + * S-mode:
> > + * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
> > + * Otherwise everything other than mctrctl is accessible.
> > + *
> > + * VS-mode:
> > + * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
> > + * Without hstateen.ctr raise virtual illegal inst excep.
> > + * Otherwise allow sctrctl (vsctrctl), sctrstatus, 0x200-0x2ff entry range.
> > + * Always raise illegal instruction exception for sctrdepth.
> > + */
> > +static RISCVException ctr_mmode(CPURISCVState *env, int csrno)
> > +{
> > +    /* Check if smctr-ext is present */
> > +    if (riscv_cpu_cfg(env)->ext_smctr) {
> > +        return RISCV_EXCP_NONE;
> > +    }
> > +
> > +    return RISCV_EXCP_ILLEGAL_INST;
> > +}
> > +
> > +static RISCVException ctr_smode(CPURISCVState *env, int csrno)
> > +{
> > +    const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
> > +
> > +    if (!cfg->ext_smctr && !cfg->ext_ssctr) {
> > +        return RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    RISCVException ret = smstateen_acc_ok(env, 0, SMSTATEEN0_CTR);
> > +    if (ret == RISCV_EXCP_NONE && csrno == CSR_SCTRDEPTH &&
> > +        env->virt_enabled) {
> > +        return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > +    }
> > +
> > +    return ret;
> > +}
> > +
> >  static RISCVException aia_hmode(CPURISCVState *env, int csrno)
> >  {
> >      int ret;
> > @@ -3835,6 +3877,86 @@ static RISCVException write_satp(CPURISCVState *env, int csrno,
> >      return RISCV_EXCP_NONE;
> >  }
> >
> > +static RISCVException rmw_sctrdepth(CPURISCVState *env, int csrno,
> > +                                    target_ulong *ret_val,
> > +                                    target_ulong new_val, target_ulong wr_mask)
> > +{
> > +    uint64_t mask = wr_mask & SCTRDEPTH_MASK;
> > +
> > +    if (ret_val) {
> > +        *ret_val = env->sctrdepth;
> > +    }
> > +
> > +    env->sctrdepth = (env->sctrdepth & ~mask) | (new_val & mask);
> > +
> > +    /* Correct depth. */
> > +    if (wr_mask & SCTRDEPTH_MASK) {
> > +        uint64_t depth = get_field(env->sctrdepth, SCTRDEPTH_MASK);
> > +
> > +        if (depth > SCTRDEPTH_MAX) {
> > +            depth = SCTRDEPTH_MAX;
> > +            env->sctrdepth = set_field(env->sctrdepth, SCTRDEPTH_MASK, depth);
> > +        }
> > +
> > +        /* Update sctrstatus.WRPTR with a legal value */
> > +        depth = 16 << depth;
> > +        env->sctrstatus =
> > +            env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
> > +    }
> > +
> > +    return RISCV_EXCP_NONE;
> > +}
> > +
> > +static RISCVException rmw_sctrstatus(CPURISCVState *env, int csrno,
> > +                                     target_ulong *ret_val,
> > +                                     target_ulong new_val, target_ulong wr_mask)
> > +{
> > +    uint32_t depth = 16 << get_field(env->sctrdepth, SCTRDEPTH_MASK);
> > +    uint32_t mask = wr_mask & SCTRSTATUS_MASK;
> > +
> > +    if (ret_val) {
> > +        *ret_val = env->sctrstatus;
> > +    }
> > +
> > +    env->sctrstatus = (env->sctrstatus & ~mask) | (new_val & mask);
> > +
> > +    /* Update sctrstatus.WRPTR with a legal value */
> > +    env->sctrstatus = env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
> > +
> > +    return RISCV_EXCP_NONE;
> > +}
> > +
> > +static RISCVException rmw_xctrctl(CPURISCVState *env, int csrno,
> > +                                    target_ulong *ret_val,
> > +                                    target_ulong new_val, target_ulong wr_mask)
> > +{
> > +    uint64_t csr_mask, mask = wr_mask;
> > +    uint64_t *ctl_ptr = &env->mctrctl;
> > +
> > +    if (csrno == CSR_MCTRCTL) {
> > +        csr_mask = MCTRCTL_MASK;
> > +    } else if (csrno == CSR_SCTRCTL && !env->virt_enabled) {
> > +        csr_mask = SCTRCTL_MASK;
> > +    } else {
> > +        /*
> > +         * This is for csrno == CSR_SCTRCTL and env->virt_enabled == true
> > +         * or csrno == CSR_VSCTRCTL.
> > +         */
> > +        csr_mask = VSCTRCTL_MASK;
> > +        ctl_ptr = &env->vsctrctl;
> > +    }
> > +
> > +    mask &= csr_mask;
> > +
> > +    if (ret_val) {
> > +        *ret_val = *ctl_ptr & csr_mask;
> > +    }
> > +
> > +    *ctl_ptr = (*ctl_ptr & ~mask) | (new_val & mask);
> > +
> > +    return RISCV_EXCP_NONE;
> > +}
> > +
> >  static RISCVException read_vstopi(CPURISCVState *env, int csrno,
> >                                    target_ulong *val)
> >  {
> > @@ -5771,6 +5893,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> >      [CSR_SPMBASE] =    { "spmbase", pointer_masking, read_spmbase,
> >                           write_spmbase                                      },
> >
> > +    [CSR_MCTRCTL]    = { "mctrctl",    ctr_mmode,  NULL, NULL, rmw_xctrctl },
> > +    [CSR_SCTRCTL]    = { "sctrctl",    ctr_smode,  NULL, NULL, rmw_xctrctl },
> > +    [CSR_VSCTRCTL]   = { "vsctrctl",   ctr_smode,  NULL, NULL, rmw_xctrctl },
> > +    [CSR_SCTRDEPTH]  = { "sctrdepth",  ctr_smode,  NULL, NULL, rmw_sctrdepth },
> > +    [CSR_SCTRSTATUS] = { "sctrstatus", ctr_smode,  NULL, NULL, rmw_sctrstatus },
> > +
> >      /* Performance Counters */
> >      [CSR_HPMCOUNTER3]    = { "hpmcounter3",    ctr,    read_hpmcounter },
> >      [CSR_HPMCOUNTER4]    = { "hpmcounter4",    ctr,    read_hpmcounter },
> > --
> > 2.34.1
> >
> >
Frank Chang Oct. 17, 2024, 3:04 p.m. UTC | #4
On Thu, Oct 17, 2024 at 7:18 PM Rajnesh Kanwal <rkanwal@rivosinc.com> wrote:

> On Tue, Aug 27, 2024 at 10:28 AM Frank Chang <frank.chang@sifive.com>
> wrote:
> >
> > Rajnesh Kanwal <rkanwal@rivosinc.com> 於 2024年6月19日 週三 下午11:27寫道:
> > >
> > > This commit adds support for [m|s|vs]ctrcontrol, sctrstatus and
> > > sctrdepth CSRs handling.
> > >
> > > Signed-off-by: Rajnesh Kanwal <rkanwal@rivosinc.com>
> > > ---
> > >  target/riscv/cpu.h     |   5 ++
> > >  target/riscv/cpu_cfg.h |   2 +
> > >  target/riscv/csr.c     | 128 +++++++++++++++++++++++++++++++++++++++++
> > >  3 files changed, 135 insertions(+)
> > >
> > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > > index a185e2d494..3d4d5172b8 100644
> > > --- a/target/riscv/cpu.h
> > > +++ b/target/riscv/cpu.h
> > > @@ -263,6 +263,11 @@ struct CPUArchState {
> > >      target_ulong mcause;
> > >      target_ulong mtval;  /* since: priv-1.10.0 */
> > >
> > > +    uint64_t mctrctl;
> > > +    uint32_t sctrdepth;
> > > +    uint32_t sctrstatus;
> > > +    uint64_t vsctrctl;
> > > +
> > >      /* Machine and Supervisor interrupt priorities */
> > >      uint8_t miprio[64];
> > >      uint8_t siprio[64];
> > > diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
> > > index d9354dc80a..d329a65811 100644
> > > --- a/target/riscv/cpu_cfg.h
> > > +++ b/target/riscv/cpu_cfg.h
> > > @@ -123,6 +123,8 @@ struct RISCVCPUConfig {
> > >      bool ext_zvfhmin;
> > >      bool ext_smaia;
> > >      bool ext_ssaia;
> > > +    bool ext_smctr;
> > > +    bool ext_ssctr;
> >
> > Base on: https://github.com/riscv/riscv-control-transfer-records/pull/29
> > Smctr and Ssctr depend on both S-mode and Sscsrind.
> > We should add the implied rules for Smctr and Ssctr.
> >
> > Regards,
> > Frank Chang
>
> Hi Frank,
>
> Are you referring to the checks in riscv_cpu_validate_set_extensions()?
> These checks are already present in the last patch.
>
>
> https://lore.kernel.org/qemu-riscv/20240619152708.135991-7-rkanwal@rivosinc.com/
>
>
Hi Rajnesh,

No, I was referring to the implied rules defined in:
https://github.com/qemu/qemu/blob/master/target/riscv/cpu.c#L2630

The implied rules will enable the implied extensions when the "parent"
extension is enabled.
Unless user turns them off explicitly from the command line,
which is an error and will be caught by the check rules you mentioned above.

The spec defines that:
"Smctr and Ssctr depend on both the implementation of S-mode and the
Sscsrind extension"
which means that we should add RVS and Sscsrind extensions as the implied
rules for Smctr and Ssctr respectively.

The use of the word "depends" in the spec is quite ambiguous.
But I once had a chance to ask Andrew Waterman about it,
and he replied that we should treat “depends on” or “requires” as a synonym
for “implies”.


Regards,
Frank Chang

>
> >
> > >      bool ext_sscofpmf;
> > >      bool ext_smepmp;
> > >      bool rvv_ta_all_1s;
> > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> > > index 2f92e4b717..0b5bf4d050 100644
> > > --- a/target/riscv/csr.c
> > > +++ b/target/riscv/csr.c
> > > @@ -621,6 +621,48 @@ static RISCVException
> pointer_masking(CPURISCVState *env, int csrno)
> > >      return RISCV_EXCP_ILLEGAL_INST;
> > >  }
> > >
> > > +/*
> > > + * M-mode:
> > > + * Without ext_smctr raise illegal inst excep.
> > > + * Otherwise everything is accessible to m-mode.
> > > + *
> > > + * S-mode:
> > > + * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
> > > + * Otherwise everything other than mctrctl is accessible.
> > > + *
> > > + * VS-mode:
> > > + * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
> > > + * Without hstateen.ctr raise virtual illegal inst excep.
> > > + * Otherwise allow sctrctl (vsctrctl), sctrstatus, 0x200-0x2ff entry
> range.
> > > + * Always raise illegal instruction exception for sctrdepth.
> > > + */
> > > +static RISCVException ctr_mmode(CPURISCVState *env, int csrno)
> > > +{
> > > +    /* Check if smctr-ext is present */
> > > +    if (riscv_cpu_cfg(env)->ext_smctr) {
> > > +        return RISCV_EXCP_NONE;
> > > +    }
> > > +
> > > +    return RISCV_EXCP_ILLEGAL_INST;
> > > +}
> > > +
> > > +static RISCVException ctr_smode(CPURISCVState *env, int csrno)
> > > +{
> > > +    const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
> > > +
> > > +    if (!cfg->ext_smctr && !cfg->ext_ssctr) {
> > > +        return RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    RISCVException ret = smstateen_acc_ok(env, 0, SMSTATEEN0_CTR);
> > > +    if (ret == RISCV_EXCP_NONE && csrno == CSR_SCTRDEPTH &&
> > > +        env->virt_enabled) {
> > > +        return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > +    }
> > > +
> > > +    return ret;
> > > +}
> > > +
> > >  static RISCVException aia_hmode(CPURISCVState *env, int csrno)
> > >  {
> > >      int ret;
> > > @@ -3835,6 +3877,86 @@ static RISCVException write_satp(CPURISCVState
> *env, int csrno,
> > >      return RISCV_EXCP_NONE;
> > >  }
> > >
> > > +static RISCVException rmw_sctrdepth(CPURISCVState *env, int csrno,
> > > +                                    target_ulong *ret_val,
> > > +                                    target_ulong new_val,
> target_ulong wr_mask)
> > > +{
> > > +    uint64_t mask = wr_mask & SCTRDEPTH_MASK;
> > > +
> > > +    if (ret_val) {
> > > +        *ret_val = env->sctrdepth;
> > > +    }
> > > +
> > > +    env->sctrdepth = (env->sctrdepth & ~mask) | (new_val & mask);
> > > +
> > > +    /* Correct depth. */
> > > +    if (wr_mask & SCTRDEPTH_MASK) {
> > > +        uint64_t depth = get_field(env->sctrdepth, SCTRDEPTH_MASK);
> > > +
> > > +        if (depth > SCTRDEPTH_MAX) {
> > > +            depth = SCTRDEPTH_MAX;
> > > +            env->sctrdepth = set_field(env->sctrdepth,
> SCTRDEPTH_MASK, depth);
> > > +        }
> > > +
> > > +        /* Update sctrstatus.WRPTR with a legal value */
> > > +        depth = 16 << depth;
> > > +        env->sctrstatus =
> > > +            env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
> > > +    }
> > > +
> > > +    return RISCV_EXCP_NONE;
> > > +}
> > > +
> > > +static RISCVException rmw_sctrstatus(CPURISCVState *env, int csrno,
> > > +                                     target_ulong *ret_val,
> > > +                                     target_ulong new_val,
> target_ulong wr_mask)
> > > +{
> > > +    uint32_t depth = 16 << get_field(env->sctrdepth, SCTRDEPTH_MASK);
> > > +    uint32_t mask = wr_mask & SCTRSTATUS_MASK;
> > > +
> > > +    if (ret_val) {
> > > +        *ret_val = env->sctrstatus;
> > > +    }
> > > +
> > > +    env->sctrstatus = (env->sctrstatus & ~mask) | (new_val & mask);
> > > +
> > > +    /* Update sctrstatus.WRPTR with a legal value */
> > > +    env->sctrstatus = env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK |
> (depth - 1));
> > > +
> > > +    return RISCV_EXCP_NONE;
> > > +}
> > > +
> > > +static RISCVException rmw_xctrctl(CPURISCVState *env, int csrno,
> > > +                                    target_ulong *ret_val,
> > > +                                    target_ulong new_val,
> target_ulong wr_mask)
> > > +{
> > > +    uint64_t csr_mask, mask = wr_mask;
> > > +    uint64_t *ctl_ptr = &env->mctrctl;
> > > +
> > > +    if (csrno == CSR_MCTRCTL) {
> > > +        csr_mask = MCTRCTL_MASK;
> > > +    } else if (csrno == CSR_SCTRCTL && !env->virt_enabled) {
> > > +        csr_mask = SCTRCTL_MASK;
> > > +    } else {
> > > +        /*
> > > +         * This is for csrno == CSR_SCTRCTL and env->virt_enabled ==
> true
> > > +         * or csrno == CSR_VSCTRCTL.
> > > +         */
> > > +        csr_mask = VSCTRCTL_MASK;
> > > +        ctl_ptr = &env->vsctrctl;
> > > +    }
> > > +
> > > +    mask &= csr_mask;
> > > +
> > > +    if (ret_val) {
> > > +        *ret_val = *ctl_ptr & csr_mask;
> > > +    }
> > > +
> > > +    *ctl_ptr = (*ctl_ptr & ~mask) | (new_val & mask);
> > > +
> > > +    return RISCV_EXCP_NONE;
> > > +}
> > > +
> > >  static RISCVException read_vstopi(CPURISCVState *env, int csrno,
> > >                                    target_ulong *val)
> > >  {
> > > @@ -5771,6 +5893,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> > >      [CSR_SPMBASE] =    { "spmbase", pointer_masking, read_spmbase,
> > >                           write_spmbase
>       },
> > >
> > > +    [CSR_MCTRCTL]    = { "mctrctl",    ctr_mmode,  NULL, NULL,
> rmw_xctrctl },
> > > +    [CSR_SCTRCTL]    = { "sctrctl",    ctr_smode,  NULL, NULL,
> rmw_xctrctl },
> > > +    [CSR_VSCTRCTL]   = { "vsctrctl",   ctr_smode,  NULL, NULL,
> rmw_xctrctl },
> > > +    [CSR_SCTRDEPTH]  = { "sctrdepth",  ctr_smode,  NULL, NULL,
> rmw_sctrdepth },
> > > +    [CSR_SCTRSTATUS] = { "sctrstatus", ctr_smode,  NULL, NULL,
> rmw_sctrstatus },
> > > +
> > >      /* Performance Counters */
> > >      [CSR_HPMCOUNTER3]    = { "hpmcounter3",    ctr,
> read_hpmcounter },
> > >      [CSR_HPMCOUNTER4]    = { "hpmcounter4",    ctr,
> read_hpmcounter },
> > > --
> > > 2.34.1
> > >
> > >
>
Rajnesh Kanwal Oct. 18, 2024, 10:24 a.m. UTC | #5
On Thu, Oct 17, 2024 at 4:05 PM Frank Chang <frank.chang@sifive.com> wrote:
>
> On Thu, Oct 17, 2024 at 7:18 PM Rajnesh Kanwal <rkanwal@rivosinc.com> wrote:
>>
>> On Tue, Aug 27, 2024 at 10:28 AM Frank Chang <frank.chang@sifive.com> wrote:
>> >
>> > Rajnesh Kanwal <rkanwal@rivosinc.com> 於 2024年6月19日 週三 下午11:27寫道:
>> > >
>> > > This commit adds support for [m|s|vs]ctrcontrol, sctrstatus and
>> > > sctrdepth CSRs handling.
>> > >
>> > > Signed-off-by: Rajnesh Kanwal <rkanwal@rivosinc.com>
>> > > ---
>> > >  target/riscv/cpu.h     |   5 ++
>> > >  target/riscv/cpu_cfg.h |   2 +
>> > >  target/riscv/csr.c     | 128 +++++++++++++++++++++++++++++++++++++++++
>> > >  3 files changed, 135 insertions(+)
>> > >
>> > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
>> > > index a185e2d494..3d4d5172b8 100644
>> > > --- a/target/riscv/cpu.h
>> > > +++ b/target/riscv/cpu.h
>> > > @@ -263,6 +263,11 @@ struct CPUArchState {
>> > >      target_ulong mcause;
>> > >      target_ulong mtval;  /* since: priv-1.10.0 */
>> > >
>> > > +    uint64_t mctrctl;
>> > > +    uint32_t sctrdepth;
>> > > +    uint32_t sctrstatus;
>> > > +    uint64_t vsctrctl;
>> > > +
>> > >      /* Machine and Supervisor interrupt priorities */
>> > >      uint8_t miprio[64];
>> > >      uint8_t siprio[64];
>> > > diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
>> > > index d9354dc80a..d329a65811 100644
>> > > --- a/target/riscv/cpu_cfg.h
>> > > +++ b/target/riscv/cpu_cfg.h
>> > > @@ -123,6 +123,8 @@ struct RISCVCPUConfig {
>> > >      bool ext_zvfhmin;
>> > >      bool ext_smaia;
>> > >      bool ext_ssaia;
>> > > +    bool ext_smctr;
>> > > +    bool ext_ssctr;
>> >
>> > Base on: https://github.com/riscv/riscv-control-transfer-records/pull/29
>> > Smctr and Ssctr depend on both S-mode and Sscsrind.
>> > We should add the implied rules for Smctr and Ssctr.
>> >
>> > Regards,
>> > Frank Chang
>>
>> Hi Frank,
>>
>> Are you referring to the checks in riscv_cpu_validate_set_extensions()?
>> These checks are already present in the last patch.
>>
>> https://lore.kernel.org/qemu-riscv/20240619152708.135991-7-rkanwal@rivosinc.com/
>>
>
> Hi Rajnesh,
>
> No, I was referring to the implied rules defined in:
> https://github.com/qemu/qemu/blob/master/target/riscv/cpu.c#L2630
>
> The implied rules will enable the implied extensions when the "parent" extension is enabled.
> Unless user turns them off explicitly from the command line,
> which is an error and will be caught by the check rules you mentioned above.
>
> The spec defines that:
> "Smctr and Ssctr depend on both the implementation of S-mode and the Sscsrind extension"
> which means that we should add RVS and Sscsrind extensions as the implied rules for Smctr and Ssctr respectively.
>
> The use of the word "depends" in the spec is quite ambiguous.
> But I once had a chance to ask Andrew Waterman about it,
> and he replied that we should treat “depends on” or “requires” as a synonym for “implies”.
>
>
> Regards,
> Frank Chang
>

Thanks for the explanation Frank. I will fix this in the next version.

>> >
>> >
>> > >      bool ext_sscofpmf;
>> > >      bool ext_smepmp;
>> > >      bool rvv_ta_all_1s;
>> > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
>> > > index 2f92e4b717..0b5bf4d050 100644
>> > > --- a/target/riscv/csr.c
>> > > +++ b/target/riscv/csr.c
>> > > @@ -621,6 +621,48 @@ static RISCVException pointer_masking(CPURISCVState *env, int csrno)
>> > >      return RISCV_EXCP_ILLEGAL_INST;
>> > >  }
>> > >
>> > > +/*
>> > > + * M-mode:
>> > > + * Without ext_smctr raise illegal inst excep.
>> > > + * Otherwise everything is accessible to m-mode.
>> > > + *
>> > > + * S-mode:
>> > > + * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
>> > > + * Otherwise everything other than mctrctl is accessible.
>> > > + *
>> > > + * VS-mode:
>> > > + * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
>> > > + * Without hstateen.ctr raise virtual illegal inst excep.
>> > > + * Otherwise allow sctrctl (vsctrctl), sctrstatus, 0x200-0x2ff entry range.
>> > > + * Always raise illegal instruction exception for sctrdepth.
>> > > + */
>> > > +static RISCVException ctr_mmode(CPURISCVState *env, int csrno)
>> > > +{
>> > > +    /* Check if smctr-ext is present */
>> > > +    if (riscv_cpu_cfg(env)->ext_smctr) {
>> > > +        return RISCV_EXCP_NONE;
>> > > +    }
>> > > +
>> > > +    return RISCV_EXCP_ILLEGAL_INST;
>> > > +}
>> > > +
>> > > +static RISCVException ctr_smode(CPURISCVState *env, int csrno)
>> > > +{
>> > > +    const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
>> > > +
>> > > +    if (!cfg->ext_smctr && !cfg->ext_ssctr) {
>> > > +        return RISCV_EXCP_ILLEGAL_INST;
>> > > +    }
>> > > +
>> > > +    RISCVException ret = smstateen_acc_ok(env, 0, SMSTATEEN0_CTR);
>> > > +    if (ret == RISCV_EXCP_NONE && csrno == CSR_SCTRDEPTH &&
>> > > +        env->virt_enabled) {
>> > > +        return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
>> > > +    }
>> > > +
>> > > +    return ret;
>> > > +}
>> > > +
>> > >  static RISCVException aia_hmode(CPURISCVState *env, int csrno)
>> > >  {
>> > >      int ret;
>> > > @@ -3835,6 +3877,86 @@ static RISCVException write_satp(CPURISCVState *env, int csrno,
>> > >      return RISCV_EXCP_NONE;
>> > >  }
>> > >
>> > > +static RISCVException rmw_sctrdepth(CPURISCVState *env, int csrno,
>> > > +                                    target_ulong *ret_val,
>> > > +                                    target_ulong new_val, target_ulong wr_mask)
>> > > +{
>> > > +    uint64_t mask = wr_mask & SCTRDEPTH_MASK;
>> > > +
>> > > +    if (ret_val) {
>> > > +        *ret_val = env->sctrdepth;
>> > > +    }
>> > > +
>> > > +    env->sctrdepth = (env->sctrdepth & ~mask) | (new_val & mask);
>> > > +
>> > > +    /* Correct depth. */
>> > > +    if (wr_mask & SCTRDEPTH_MASK) {
>> > > +        uint64_t depth = get_field(env->sctrdepth, SCTRDEPTH_MASK);
>> > > +
>> > > +        if (depth > SCTRDEPTH_MAX) {
>> > > +            depth = SCTRDEPTH_MAX;
>> > > +            env->sctrdepth = set_field(env->sctrdepth, SCTRDEPTH_MASK, depth);
>> > > +        }
>> > > +
>> > > +        /* Update sctrstatus.WRPTR with a legal value */
>> > > +        depth = 16 << depth;
>> > > +        env->sctrstatus =
>> > > +            env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
>> > > +    }
>> > > +
>> > > +    return RISCV_EXCP_NONE;
>> > > +}
>> > > +
>> > > +static RISCVException rmw_sctrstatus(CPURISCVState *env, int csrno,
>> > > +                                     target_ulong *ret_val,
>> > > +                                     target_ulong new_val, target_ulong wr_mask)
>> > > +{
>> > > +    uint32_t depth = 16 << get_field(env->sctrdepth, SCTRDEPTH_MASK);
>> > > +    uint32_t mask = wr_mask & SCTRSTATUS_MASK;
>> > > +
>> > > +    if (ret_val) {
>> > > +        *ret_val = env->sctrstatus;
>> > > +    }
>> > > +
>> > > +    env->sctrstatus = (env->sctrstatus & ~mask) | (new_val & mask);
>> > > +
>> > > +    /* Update sctrstatus.WRPTR with a legal value */
>> > > +    env->sctrstatus = env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
>> > > +
>> > > +    return RISCV_EXCP_NONE;
>> > > +}
>> > > +
>> > > +static RISCVException rmw_xctrctl(CPURISCVState *env, int csrno,
>> > > +                                    target_ulong *ret_val,
>> > > +                                    target_ulong new_val, target_ulong wr_mask)
>> > > +{
>> > > +    uint64_t csr_mask, mask = wr_mask;
>> > > +    uint64_t *ctl_ptr = &env->mctrctl;
>> > > +
>> > > +    if (csrno == CSR_MCTRCTL) {
>> > > +        csr_mask = MCTRCTL_MASK;
>> > > +    } else if (csrno == CSR_SCTRCTL && !env->virt_enabled) {
>> > > +        csr_mask = SCTRCTL_MASK;
>> > > +    } else {
>> > > +        /*
>> > > +         * This is for csrno == CSR_SCTRCTL and env->virt_enabled == true
>> > > +         * or csrno == CSR_VSCTRCTL.
>> > > +         */
>> > > +        csr_mask = VSCTRCTL_MASK;
>> > > +        ctl_ptr = &env->vsctrctl;
>> > > +    }
>> > > +
>> > > +    mask &= csr_mask;
>> > > +
>> > > +    if (ret_val) {
>> > > +        *ret_val = *ctl_ptr & csr_mask;
>> > > +    }
>> > > +
>> > > +    *ctl_ptr = (*ctl_ptr & ~mask) | (new_val & mask);
>> > > +
>> > > +    return RISCV_EXCP_NONE;
>> > > +}
>> > > +
>> > >  static RISCVException read_vstopi(CPURISCVState *env, int csrno,
>> > >                                    target_ulong *val)
>> > >  {
>> > > @@ -5771,6 +5893,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>> > >      [CSR_SPMBASE] =    { "spmbase", pointer_masking, read_spmbase,
>> > >                           write_spmbase                                      },
>> > >
>> > > +    [CSR_MCTRCTL]    = { "mctrctl",    ctr_mmode,  NULL, NULL, rmw_xctrctl },
>> > > +    [CSR_SCTRCTL]    = { "sctrctl",    ctr_smode,  NULL, NULL, rmw_xctrctl },
>> > > +    [CSR_VSCTRCTL]   = { "vsctrctl",   ctr_smode,  NULL, NULL, rmw_xctrctl },
>> > > +    [CSR_SCTRDEPTH]  = { "sctrdepth",  ctr_smode,  NULL, NULL, rmw_sctrdepth },
>> > > +    [CSR_SCTRSTATUS] = { "sctrstatus", ctr_smode,  NULL, NULL, rmw_sctrstatus },
>> > > +
>> > >      /* Performance Counters */
>> > >      [CSR_HPMCOUNTER3]    = { "hpmcounter3",    ctr,    read_hpmcounter },
>> > >      [CSR_HPMCOUNTER4]    = { "hpmcounter4",    ctr,    read_hpmcounter },
>> > > --
>> > > 2.34.1
>> > >
>> > >
diff mbox series

Patch

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index a185e2d494..3d4d5172b8 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -263,6 +263,11 @@  struct CPUArchState {
     target_ulong mcause;
     target_ulong mtval;  /* since: priv-1.10.0 */
 
+    uint64_t mctrctl;
+    uint32_t sctrdepth;
+    uint32_t sctrstatus;
+    uint64_t vsctrctl;
+
     /* Machine and Supervisor interrupt priorities */
     uint8_t miprio[64];
     uint8_t siprio[64];
diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
index d9354dc80a..d329a65811 100644
--- a/target/riscv/cpu_cfg.h
+++ b/target/riscv/cpu_cfg.h
@@ -123,6 +123,8 @@  struct RISCVCPUConfig {
     bool ext_zvfhmin;
     bool ext_smaia;
     bool ext_ssaia;
+    bool ext_smctr;
+    bool ext_ssctr;
     bool ext_sscofpmf;
     bool ext_smepmp;
     bool rvv_ta_all_1s;
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 2f92e4b717..0b5bf4d050 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -621,6 +621,48 @@  static RISCVException pointer_masking(CPURISCVState *env, int csrno)
     return RISCV_EXCP_ILLEGAL_INST;
 }
 
+/*
+ * M-mode:
+ * Without ext_smctr raise illegal inst excep.
+ * Otherwise everything is accessible to m-mode.
+ *
+ * S-mode:
+ * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
+ * Otherwise everything other than mctrctl is accessible.
+ *
+ * VS-mode:
+ * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
+ * Without hstateen.ctr raise virtual illegal inst excep.
+ * Otherwise allow sctrctl (vsctrctl), sctrstatus, 0x200-0x2ff entry range.
+ * Always raise illegal instruction exception for sctrdepth.
+ */
+static RISCVException ctr_mmode(CPURISCVState *env, int csrno)
+{
+    /* Check if smctr-ext is present */
+    if (riscv_cpu_cfg(env)->ext_smctr) {
+        return RISCV_EXCP_NONE;
+    }
+
+    return RISCV_EXCP_ILLEGAL_INST;
+}
+
+static RISCVException ctr_smode(CPURISCVState *env, int csrno)
+{
+    const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
+
+    if (!cfg->ext_smctr && !cfg->ext_ssctr) {
+        return RISCV_EXCP_ILLEGAL_INST;
+    }
+
+    RISCVException ret = smstateen_acc_ok(env, 0, SMSTATEEN0_CTR);
+    if (ret == RISCV_EXCP_NONE && csrno == CSR_SCTRDEPTH &&
+        env->virt_enabled) {
+        return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+    }
+
+    return ret;
+}
+
 static RISCVException aia_hmode(CPURISCVState *env, int csrno)
 {
     int ret;
@@ -3835,6 +3877,86 @@  static RISCVException write_satp(CPURISCVState *env, int csrno,
     return RISCV_EXCP_NONE;
 }
 
+static RISCVException rmw_sctrdepth(CPURISCVState *env, int csrno,
+                                    target_ulong *ret_val,
+                                    target_ulong new_val, target_ulong wr_mask)
+{
+    uint64_t mask = wr_mask & SCTRDEPTH_MASK;
+
+    if (ret_val) {
+        *ret_val = env->sctrdepth;
+    }
+
+    env->sctrdepth = (env->sctrdepth & ~mask) | (new_val & mask);
+
+    /* Correct depth. */
+    if (wr_mask & SCTRDEPTH_MASK) {
+        uint64_t depth = get_field(env->sctrdepth, SCTRDEPTH_MASK);
+
+        if (depth > SCTRDEPTH_MAX) {
+            depth = SCTRDEPTH_MAX;
+            env->sctrdepth = set_field(env->sctrdepth, SCTRDEPTH_MASK, depth);
+        }
+
+        /* Update sctrstatus.WRPTR with a legal value */
+        depth = 16 << depth;
+        env->sctrstatus =
+            env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
+    }
+
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException rmw_sctrstatus(CPURISCVState *env, int csrno,
+                                     target_ulong *ret_val,
+                                     target_ulong new_val, target_ulong wr_mask)
+{
+    uint32_t depth = 16 << get_field(env->sctrdepth, SCTRDEPTH_MASK);
+    uint32_t mask = wr_mask & SCTRSTATUS_MASK;
+
+    if (ret_val) {
+        *ret_val = env->sctrstatus;
+    }
+
+    env->sctrstatus = (env->sctrstatus & ~mask) | (new_val & mask);
+
+    /* Update sctrstatus.WRPTR with a legal value */
+    env->sctrstatus = env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
+
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException rmw_xctrctl(CPURISCVState *env, int csrno,
+                                    target_ulong *ret_val,
+                                    target_ulong new_val, target_ulong wr_mask)
+{
+    uint64_t csr_mask, mask = wr_mask;
+    uint64_t *ctl_ptr = &env->mctrctl;
+
+    if (csrno == CSR_MCTRCTL) {
+        csr_mask = MCTRCTL_MASK;
+    } else if (csrno == CSR_SCTRCTL && !env->virt_enabled) {
+        csr_mask = SCTRCTL_MASK;
+    } else {
+        /*
+         * This is for csrno == CSR_SCTRCTL and env->virt_enabled == true
+         * or csrno == CSR_VSCTRCTL.
+         */
+        csr_mask = VSCTRCTL_MASK;
+        ctl_ptr = &env->vsctrctl;
+    }
+
+    mask &= csr_mask;
+
+    if (ret_val) {
+        *ret_val = *ctl_ptr & csr_mask;
+    }
+
+    *ctl_ptr = (*ctl_ptr & ~mask) | (new_val & mask);
+
+    return RISCV_EXCP_NONE;
+}
+
 static RISCVException read_vstopi(CPURISCVState *env, int csrno,
                                   target_ulong *val)
 {
@@ -5771,6 +5893,12 @@  riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
     [CSR_SPMBASE] =    { "spmbase", pointer_masking, read_spmbase,
                          write_spmbase                                      },
 
+    [CSR_MCTRCTL]    = { "mctrctl",    ctr_mmode,  NULL, NULL, rmw_xctrctl },
+    [CSR_SCTRCTL]    = { "sctrctl",    ctr_smode,  NULL, NULL, rmw_xctrctl },
+    [CSR_VSCTRCTL]   = { "vsctrctl",   ctr_smode,  NULL, NULL, rmw_xctrctl },
+    [CSR_SCTRDEPTH]  = { "sctrdepth",  ctr_smode,  NULL, NULL, rmw_sctrdepth },
+    [CSR_SCTRSTATUS] = { "sctrstatus", ctr_smode,  NULL, NULL, rmw_sctrstatus },
+
     /* Performance Counters */
     [CSR_HPMCOUNTER3]    = { "hpmcounter3",    ctr,    read_hpmcounter },
     [CSR_HPMCOUNTER4]    = { "hpmcounter4",    ctr,    read_hpmcounter },