diff options
Diffstat (limited to 'target/riscv/csr.c')
-rw-r--r-- | target/riscv/csr.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 3ddf309..04b06a2 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -22,6 +22,7 @@ #include "qemu/timer.h" #include "cpu.h" #include "pmu.h" +#include "time_helper.h" #include "qemu/main-loop.h" #include "exec/exec-all.h" #include "sysemu/cpu-timers.h" @@ -815,6 +816,81 @@ static RISCVException read_timeh(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static RISCVException sstc(CPURISCVState *env, int csrno) +{ + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + + if (!cpu->cfg.ext_sstc || !env->rdtime_fn) { + return RISCV_EXCP_ILLEGAL_INST; + } + + if (env->priv == PRV_M) { + return RISCV_EXCP_NONE; + } + + /* + * No need of separate function for rv32 as menvcfg stores both menvcfg + * menvcfgh for RV32. + */ + if (!(get_field(env->mcounteren, COUNTEREN_TM) && + get_field(env->menvcfg, MENVCFG_STCE))) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return smode(env, csrno); +} + +static RISCVException sstc_32(CPURISCVState *env, int csrno) +{ + if (riscv_cpu_mxl(env) != MXL_RV32) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return sstc(env, csrno); +} + +static RISCVException read_stimecmp(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->stimecmp; + return RISCV_EXCP_NONE; +} + +static RISCVException read_stimecmph(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->stimecmp >> 32; + return RISCV_EXCP_NONE; +} + +static RISCVException write_stimecmp(CPURISCVState *env, int csrno, + target_ulong val) +{ + RISCVCPU *cpu = env_archcpu(env); + + if (riscv_cpu_mxl(env) == MXL_RV32) { + env->stimecmp = deposit64(env->stimecmp, 0, 32, (uint64_t)val); + } else { + env->stimecmp = val; + } + + riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP); + + return RISCV_EXCP_NONE; +} + +static RISCVException write_stimecmph(CPURISCVState *env, int csrno, + target_ulong val) +{ + RISCVCPU *cpu = env_archcpu(env); + + env->stimecmp = deposit64(env->stimecmp, 32, 32, (uint64_t)val); + riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP); + + return RISCV_EXCP_NONE; +} + /* Machine constants */ #define M_MODE_INTERRUPTS ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP)) @@ -1723,6 +1799,12 @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno, new_val |= env->external_seip * MIP_SEIP; } + if (cpu->cfg.ext_sstc && (env->priv == PRV_M) && + get_field(env->menvcfg, MENVCFG_STCE)) { + /* sstc extension forbids STIP & VSTIP to be writeable in mip */ + mask = mask & ~(MIP_STIP | MIP_VSTIP); + } + if (mask) { old_mip = riscv_cpu_update_mip(cpu, mask, (new_val & mask)); } else { @@ -3594,6 +3676,10 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_SCAUSE] = { "scause", smode, read_scause, write_scause }, [CSR_STVAL] = { "stval", smode, read_stval, write_stval }, [CSR_SIP] = { "sip", smode, NULL, NULL, rmw_sip }, + [CSR_STIMECMP] = { "stimecmp", sstc, read_stimecmp, write_stimecmp, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_STIMECMPH] = { "stimecmph", sstc_32, read_stimecmph, write_stimecmph, + .min_priv_ver = PRIV_VERSION_1_12_0 }, /* Supervisor Protection and Translation */ [CSR_SATP] = { "satp", smode, read_satp, write_satp }, |