On Wed, Apr 9, 2025 at 12:52 PM 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>
Acked-by: Alistair Francis <alistair.fran...@wdc.com> Alistair > --- > target/riscv/csr.c | 44 ++++++++++++++++++++++++++++++++++++ > target/riscv/time_helper.c | 46 ++++++++++++++++++++++++++++++++++++++ > target/riscv/time_helper.h | 1 + > 3 files changed, 91 insertions(+) > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c > index e86808fd98..548daf6a7a 100644 > --- a/target/riscv/csr.c > +++ b/target/riscv/csr.c > @@ -3161,6 +3161,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) | > @@ -3186,10 +3187,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; > } > > @@ -3212,6 +3222,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; > @@ -3220,6 +3236,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; > } > > @@ -3297,8 +3317,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) { > @@ -3324,6 +3346,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; > @@ -3331,6 +3358,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; > } > > @@ -3352,19 +3383,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..400e917354 100644 > --- a/target/riscv/time_helper.c > +++ b/target/riscv/time_helper.c > @@ -140,6 +140,52 @@ 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 (enable) { > + riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp, > + env->htimedelta, MIP_VSTIP); > + } else { > + riscv_timer_disable_timecmp(env, env->vstimer, MIP_VSTIP); > + } > + > + if (is_m_mode) { > + if (enable) { > + riscv_timer_write_timecmp(env, env->stimer, env->stimecmp, 0, > MIP_STIP); > + } else { > + riscv_timer_disable_timecmp(env, env->stimer, MIP_STIP); > + } > + } > +} > + > 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 > >