On Thu, Mar 20, 2025 at 5:24 AM Jim Shu <jim....@sifive.com> wrote: > > Updating STCE will enable/disable SSTC in S-mode or/and VS-mode, so we > also need to update S/VS-mode Timer and S/VSTIP bits in $mip CSR. > > Signed-off-by: Jim Shu <jim....@sifive.com> > --- > target/riscv/csr.c | 44 ++++++++++++++++++++++++++++++++ > target/riscv/time_helper.c | 51 ++++++++++++++++++++++++++++++++++++++ > target/riscv/time_helper.h | 1 + > 3 files changed, 96 insertions(+) > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c > index ba026dfc8e..c954e49cae 100644 > --- a/target/riscv/csr.c > +++ b/target/riscv/csr.c > @@ -3156,6 +3156,7 @@ static RISCVException write_menvcfg(CPURISCVState *env, > int csrno, > const RISCVCPUConfig *cfg = riscv_cpu_cfg(env); > uint64_t mask = MENVCFG_FIOM | MENVCFG_CBIE | MENVCFG_CBCFE | > MENVCFG_CBZE | MENVCFG_CDE; > + bool stce_changed = false; > > if (riscv_cpu_mxl(env) == MXL_RV64) { > mask |= (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) | > @@ -3181,10 +3182,19 @@ static RISCVException write_menvcfg(CPURISCVState > *env, int csrno, > if ((val & MENVCFG_DTE) == 0) { > env->mstatus &= ~MSTATUS_SDT; > } > + > + if (cfg->ext_sstc && > + ((env->menvcfg & MENVCFG_STCE) != (val & MENVCFG_STCE))) { > + stce_changed = true; > + } > } > env->menvcfg = (env->menvcfg & ~mask) | (val & mask); > write_henvcfg(env, CSR_HENVCFG, env->henvcfg); > > + if (stce_changed) { > + riscv_timer_stce_changed(env, true, !!(val & MENVCFG_STCE)); > + } > + > return RISCV_EXCP_NONE; > } > > @@ -3207,6 +3217,12 @@ static RISCVException write_menvcfgh(CPURISCVState > *env, int csrno, > (cfg->ext_smcdeleg ? MENVCFG_CDE : 0) | > (cfg->ext_ssdbltrp ? MENVCFG_DTE : 0); > uint64_t valh = (uint64_t)val << 32; > + bool stce_changed = false; > + > + if (cfg->ext_sstc && > + ((env->menvcfg & MENVCFG_STCE) != (valh & MENVCFG_STCE))) { > + stce_changed = true; > + } > > if ((valh & MENVCFG_DTE) == 0) { > env->mstatus &= ~MSTATUS_SDT; > @@ -3215,6 +3231,10 @@ static RISCVException write_menvcfgh(CPURISCVState > *env, int csrno, > env->menvcfg = (env->menvcfg & ~mask) | (valh & mask); > write_henvcfgh(env, CSR_HENVCFGH, env->henvcfg >> 32); > > + if (stce_changed) { > + riscv_timer_stce_changed(env, true, !!(valh & MENVCFG_STCE)); > + } > + > return RISCV_EXCP_NONE; > } > > @@ -3292,8 +3312,10 @@ static RISCVException read_henvcfg(CPURISCVState *env, > int csrno, > static RISCVException write_henvcfg(CPURISCVState *env, int csrno, > target_ulong val) > { > + const RISCVCPUConfig *cfg = riscv_cpu_cfg(env); > uint64_t mask = HENVCFG_FIOM | HENVCFG_CBIE | HENVCFG_CBCFE | > HENVCFG_CBZE; > RISCVException ret; > + bool stce_changed = false; > > ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG); > if (ret != RISCV_EXCP_NONE) { > @@ -3319,6 +3341,11 @@ static RISCVException write_henvcfg(CPURISCVState > *env, int csrno, > get_field(val, HENVCFG_PMM) != PMM_FIELD_RESERVED) { > mask |= HENVCFG_PMM; > } > + > + if (cfg->ext_sstc && > + ((env->henvcfg & HENVCFG_STCE) != (val & HENVCFG_STCE))) { > + stce_changed = true; > + } > } > > env->henvcfg = val & mask; > @@ -3326,6 +3353,10 @@ static RISCVException write_henvcfg(CPURISCVState > *env, int csrno, > env->vsstatus &= ~MSTATUS_SDT; > } > > + if (stce_changed) { > + riscv_timer_stce_changed(env, false, !!(val & HENVCFG_STCE)); > + } > + > return RISCV_EXCP_NONE; > } > > @@ -3347,19 +3378,32 @@ static RISCVException read_henvcfgh(CPURISCVState > *env, int csrno, > static RISCVException write_henvcfgh(CPURISCVState *env, int csrno, > target_ulong val) > { > + const RISCVCPUConfig *cfg = riscv_cpu_cfg(env); > uint64_t mask = env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE | > HENVCFG_ADUE | HENVCFG_DTE); > uint64_t valh = (uint64_t)val << 32; > RISCVException ret; > + bool stce_changed = false; > > ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG); > if (ret != RISCV_EXCP_NONE) { > return ret; > } > + > + if (cfg->ext_sstc && > + ((env->henvcfg & HENVCFG_STCE) != (valh & HENVCFG_STCE))) { > + stce_changed = true; > + } > + > env->henvcfg = (env->henvcfg & 0xFFFFFFFF) | (valh & mask); > if ((env->henvcfg & HENVCFG_DTE) == 0) { > env->vsstatus &= ~MSTATUS_SDT; > } > + > + if (stce_changed) { > + riscv_timer_stce_changed(env, false, !!(val & HENVCFG_STCE)); > + } > + > return RISCV_EXCP_NONE; > } > > diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c > index aebf0798d0..c648c9fac7 100644 > --- a/target/riscv/time_helper.c > +++ b/target/riscv/time_helper.c > @@ -140,6 +140,57 @@ void riscv_timer_write_timecmp(CPURISCVState *env, > QEMUTimer *timer, > timer_mod(timer, next); > } > > +/* > + * When disabling xenvcfg.STCE, the S/VS Timer may be disabled at the same > time. > + * It is safe to call this function regardless of whether the timer has been > + * deleted or not. timer_del() will do nothing if the timer has already > + * been deleted. > + */ > +static void riscv_timer_disable_timecmp(CPURISCVState *env, QEMUTimer *timer, > + uint32_t timer_irq) > +{ > + /* Disable S-mode Timer IRQ and HW-based STIP */ > + if ((timer_irq == MIP_STIP) && !get_field(env->menvcfg, MENVCFG_STCE)) { > + riscv_cpu_update_mip(env, timer_irq, BOOL_TO_MASK(0)); > + timer_del(timer); > + return; > + } > + > + /* Disable VS-mode Timer IRQ and HW-based VSTIP */ > + if ((timer_irq == MIP_VSTIP) && > + (!get_field(env->menvcfg, MENVCFG_STCE) || > + !get_field(env->henvcfg, HENVCFG_STCE))) { > + env->vstime_irq = 0; > + riscv_cpu_update_mip(env, 0, BOOL_TO_MASK(0)); > + timer_del(timer); > + return; > + } > +} > + > +/* Enable or disable S/VS-mode Timer when xenvcfg.STCE is changed */ > +void riscv_timer_stce_changed(CPURISCVState *env, bool is_m_mode, bool > enable) > +{ > + if (is_m_mode) { > + /* menvcfg.STCE changes */ > + if (enable) { > + riscv_timer_write_timecmp(env, env->stimer, env->stimecmp, 0, > MIP_STIP); > + riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp, > + env->htimedelta, MIP_VSTIP);
This line and ... > + } else { > + riscv_timer_disable_timecmp(env, env->stimer, MIP_STIP); > + riscv_timer_disable_timecmp(env, env->vstimer, MIP_VSTIP); This line are duplicated below. > + } > + } else { We can remove the else > + /* henvcfg.STCE changes */ > + if (enable) { > + riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp, > + env->htimedelta, MIP_VSTIP); > + } else { > + riscv_timer_disable_timecmp(env, env->vstimer, MIP_VSTIP); > + } and always run this branch to remove the duplicated code above Alistair > + } > +} > + > void riscv_timer_init(RISCVCPU *cpu) > { > CPURISCVState *env; > diff --git a/target/riscv/time_helper.h b/target/riscv/time_helper.h > index cacd79b80c..af1f634f89 100644 > --- a/target/riscv/time_helper.h > +++ b/target/riscv/time_helper.h > @@ -25,6 +25,7 @@ > void riscv_timer_write_timecmp(CPURISCVState *env, QEMUTimer *timer, > uint64_t timecmp, uint64_t delta, > uint32_t timer_irq); > +void riscv_timer_stce_changed(CPURISCVState *env, bool is_m_mode, bool > enable); > void riscv_timer_init(RISCVCPU *cpu); > > #endif > -- > 2.17.1 > >