aboutsummaryrefslogtreecommitdiff
path: root/target/riscv/csr.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/riscv/csr.c')
-rw-r--r--target/riscv/csr.c86
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 },