The specification states that menvcfg.STCE=0 prevents both *stimecmp CSRs from having an effect on the pending interrupts. henvcfg.STCE=0 disables only vstimecmp.
Make sure that when *envcfg.STCE is not set: * writing the *stimecmp CSRs doesn't modify the *ip CSRs, * and that the interrupt timer is disarmed. Call the *stimecmp CSR update functions when *envcfg.STCE is toggled, because the *ip CSRs need to immediately reflect the new behavior. Fixes: 43888c2f1823 ("target/riscv: Add stimecmp support") Signed-off-by: Radim Krčmář <rkrc...@ventanamicro.com> --- target/riscv/csr.c | 12 ++++++++++++ target/riscv/time_helper.c | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index fb149721691d..43eae9bcf153 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -3181,6 +3181,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; + typeof(env->menvcfg) old = env->menvcfg; if (riscv_cpu_mxl(env) == MXL_RV64) { mask |= (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) | @@ -3208,6 +3209,11 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno, } } env->menvcfg = (env->menvcfg & ~mask) | (val & mask); + + if ((old ^ env->menvcfg) & MENVCFG_STCE) { + riscv_timer_write_timecmp(env, env->stimer, env->stimecmp, 0, MIP_STIP); + } + return write_henvcfg(env, CSR_HENVCFG, env->henvcfg, ra); } @@ -3314,6 +3320,7 @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { uint64_t mask = HENVCFG_FIOM | HENVCFG_CBIE | HENVCFG_CBCFE | HENVCFG_CBZE; + typeof(env->henvcfg) old = env->henvcfg; RISCVException ret; ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG); @@ -3347,6 +3354,11 @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno, env->vsstatus &= ~MSTATUS_SDT; } + if ((old ^ env->henvcfg) & HENVCFG_STCE) { + riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp, + env->htimedelta, MIP_VSTIP); + } + return RISCV_EXCP_NONE; } diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c index bc0d9a0c4c35..8198a2d8d92d 100644 --- a/target/riscv/time_helper.c +++ b/target/riscv/time_helper.c @@ -49,6 +49,16 @@ void riscv_timer_write_timecmp(CPURISCVState *env, QEMUTimer *timer, uint32_t timebase_freq = mtimer->timebase_freq; uint64_t rtc_r = env->rdtime_fn(env->rdtime_fn_arg) + delta; + /* + * *envcfg.STCE disables *stimecmp interrupts, but still allows higher + * privileges to write the *stimecmp CSRs. + */ + if (!get_field(env->menvcfg, MENVCFG_STCE) || + (timer_irq == MIP_VSTIP && !get_field(env->henvcfg, HENVCFG_STCE))) { + timer_del(timer); + return; + } + if (timecmp <= rtc_r) { /* * If we're setting an stimecmp value in the "past", -- 2.49.0