#include "time_helper.h"
#include "qemu/main-loop.h"
#include "exec/exec-all.h"
+#include "exec/tb-flush.h"
#include "sysemu/cpu-timers.h"
#include "qemu/guest-random.h"
#include "qapi/error.h"
}
/* Predicates */
+#if !defined(CONFIG_USER_ONLY)
+RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit)
+{
+ bool virt = env->virt_enabled;
+
+ if (env->priv == PRV_M || !riscv_cpu_cfg(env)->ext_smstateen) {
+ return RISCV_EXCP_NONE;
+ }
+
+ if (!(env->mstateen[index] & bit)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ if (virt) {
+ if (!(env->hstateen[index] & bit)) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+
+ if (env->priv == PRV_U && !(env->sstateen[index] & bit)) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ }
+
+ if (env->priv == PRV_U && riscv_has_ext(env, RVS)) {
+ if (!(env->sstateen[index] & bit)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ }
+
+ return RISCV_EXCP_NONE;
+}
+#endif
+
static RISCVException fs(CPURISCVState *env, int csrno)
{
#if !defined(CONFIG_USER_ONLY)
if (!env->debugger && !riscv_cpu_fp_enabled(env) &&
- !RISCV_CPU(env_cpu(env))->cfg.ext_zfinx) {
+ !riscv_cpu_cfg(env)->ext_zfinx) {
return RISCV_EXCP_ILLEGAL_INST;
}
#endif
static RISCVException vs(CPURISCVState *env, int csrno)
{
- CPUState *cs = env_cpu(env);
- RISCVCPU *cpu = RISCV_CPU(cs);
-
- if (env->misa_ext & RVV ||
- cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) {
+ if (riscv_cpu_cfg(env)->ext_zve32f) {
#if !defined(CONFIG_USER_ONLY)
if (!env->debugger && !riscv_cpu_vector_enabled(env)) {
return RISCV_EXCP_ILLEGAL_INST;
static RISCVException ctr(CPURISCVState *env, int csrno)
{
#if !defined(CONFIG_USER_ONLY)
- CPUState *cs = env_cpu(env);
- RISCVCPU *cpu = RISCV_CPU(cs);
+ RISCVCPU *cpu = env_archcpu(env);
int ctr_index;
target_ulong ctr_mask;
int base_csrno = CSR_CYCLE;
skip_ext_pmu_check:
+ if (env->debugger) {
+ return RISCV_EXCP_NONE;
+ }
+
if (env->priv < PRV_M && !get_field(env->mcounteren, ctr_mask)) {
return RISCV_EXCP_ILLEGAL_INST;
}
- if (riscv_cpu_virt_enabled(env)) {
+ if (env->virt_enabled) {
if (!get_field(env->hcounteren, ctr_mask) ||
(env->priv == PRV_U && !get_field(env->scounteren, ctr_mask))) {
return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
return ctr(env, csrno);
}
+static RISCVException zcmt(CPURISCVState *env, int csrno)
+{
+ if (!riscv_cpu_cfg(env)->ext_zcmt) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+#if !defined(CONFIG_USER_ONLY)
+ RISCVException ret = smstateen_acc_ok(env, 0, SMSTATEEN0_JVT);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+#endif
+
+ return RISCV_EXCP_NONE;
+}
+
#if !defined(CONFIG_USER_ONLY)
static RISCVException mctr(CPURISCVState *env, int csrno)
{
- CPUState *cs = env_cpu(env);
- RISCVCPU *cpu = RISCV_CPU(cs);
+ int pmu_num = riscv_cpu_cfg(env)->pmu_num;
int ctr_index;
int base_csrno = CSR_MHPMCOUNTER3;
base_csrno += 0x80;
}
ctr_index = csrno - base_csrno;
- if (!cpu->cfg.pmu_num || ctr_index >= cpu->cfg.pmu_num) {
- /* The PMU is not enabled or counter is out of range*/
+ if (!pmu_num || ctr_index >= pmu_num) {
+ /* The PMU is not enabled or counter is out of range */
return RISCV_EXCP_ILLEGAL_INST;
}
static RISCVException sscofpmf(CPURISCVState *env, int csrno)
{
- CPUState *cs = env_cpu(env);
- RISCVCPU *cpu = RISCV_CPU(cs);
-
- if (!cpu->cfg.ext_sscofpmf) {
+ if (!riscv_cpu_cfg(env)->ext_sscofpmf) {
return RISCV_EXCP_ILLEGAL_INST;
}
static int aia_any(CPURISCVState *env, int csrno)
{
- RISCVCPU *cpu = env_archcpu(env);
-
- if (!cpu->cfg.ext_smaia) {
+ if (!riscv_cpu_cfg(env)->ext_smaia) {
return RISCV_EXCP_ILLEGAL_INST;
}
static int aia_any32(CPURISCVState *env, int csrno)
{
- RISCVCPU *cpu = env_archcpu(env);
-
- if (!cpu->cfg.ext_smaia) {
+ if (!riscv_cpu_cfg(env)->ext_smaia) {
return RISCV_EXCP_ILLEGAL_INST;
}
static int aia_smode(CPURISCVState *env, int csrno)
{
- RISCVCPU *cpu = env_archcpu(env);
-
- if (!cpu->cfg.ext_ssaia) {
+ if (!riscv_cpu_cfg(env)->ext_ssaia) {
return RISCV_EXCP_ILLEGAL_INST;
}
static int aia_smode32(CPURISCVState *env, int csrno)
{
- RISCVCPU *cpu = env_archcpu(env);
-
- if (!cpu->cfg.ext_ssaia) {
+ if (!riscv_cpu_cfg(env)->ext_ssaia) {
return RISCV_EXCP_ILLEGAL_INST;
}
return umode(env, csrno);
}
+static RISCVException mstateen(CPURISCVState *env, int csrno)
+{
+ if (!riscv_cpu_cfg(env)->ext_smstateen) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return any(env, csrno);
+}
+
+static RISCVException hstateen_pred(CPURISCVState *env, int csrno, int base)
+{
+ if (!riscv_cpu_cfg(env)->ext_smstateen) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ RISCVException ret = hmode(env, csrno);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
+ if (env->debugger) {
+ return RISCV_EXCP_NONE;
+ }
+
+ if (env->priv < PRV_M) {
+ if (!(env->mstateen[csrno - base] & SMSTATEEN_STATEEN)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException hstateen(CPURISCVState *env, int csrno)
+{
+ return hstateen_pred(env, csrno, CSR_HSTATEEN0);
+}
+
+static RISCVException hstateenh(CPURISCVState *env, int csrno)
+{
+ return hstateen_pred(env, csrno, CSR_HSTATEEN0H);
+}
+
+static RISCVException sstateen(CPURISCVState *env, int csrno)
+{
+ bool virt = env->virt_enabled;
+ int index = csrno - CSR_SSTATEEN0;
+
+ if (!riscv_cpu_cfg(env)->ext_smstateen) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ RISCVException ret = smode(env, csrno);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
+ if (env->debugger) {
+ return RISCV_EXCP_NONE;
+ }
+
+ if (env->priv < PRV_M) {
+ if (!(env->mstateen[index] & SMSTATEEN_STATEEN)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ if (virt) {
+ if (!(env->hstateen[index] & SMSTATEEN_STATEEN)) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ }
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException sstc(CPURISCVState *env, int csrno)
+{
+ bool hmode_check = false;
+
+ if (!riscv_cpu_cfg(env)->ext_sstc || !env->rdtime_fn) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ if ((csrno == CSR_VSTIMECMP) || (csrno == CSR_VSTIMECMPH)) {
+ hmode_check = true;
+ }
+
+ RISCVException ret = hmode_check ? hmode(env, csrno) : smode(env, csrno);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
+ if (env->debugger) {
+ return RISCV_EXCP_NONE;
+ }
+
+ 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;
+ }
+
+ if (env->virt_enabled) {
+ if (!(get_field(env->hcounteren, COUNTEREN_TM) &&
+ get_field(env->henvcfg, HENVCFG_STCE))) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+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 satp(CPURISCVState *env, int csrno)
+{
+ if (env->priv == PRV_S && !env->virt_enabled &&
+ get_field(env->mstatus, MSTATUS_TVM)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ if (env->priv == PRV_S && env->virt_enabled &&
+ get_field(env->hstatus, HSTATUS_VTVM)) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+
+ return smode(env, csrno);
+}
+
+static RISCVException hgatp(CPURISCVState *env, int csrno)
+{
+ if (env->priv == PRV_S && !env->virt_enabled &&
+ get_field(env->mstatus, MSTATUS_TVM)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return hmode(env, csrno);
+}
+
/* Checks if PointerMasking registers could be accessed */
static RISCVException pointer_masking(CPURISCVState *env, int csrno)
{
static int aia_hmode(CPURISCVState *env, int csrno)
{
- RISCVCPU *cpu = env_archcpu(env);
-
- if (!cpu->cfg.ext_ssaia) {
+ if (!riscv_cpu_cfg(env)->ext_ssaia) {
return RISCV_EXCP_ILLEGAL_INST;
}
static int aia_hmode32(CPURISCVState *env, int csrno)
{
- RISCVCPU *cpu = env_archcpu(env);
-
- if (!cpu->cfg.ext_ssaia) {
+ if (!riscv_cpu_cfg(env)->ext_ssaia) {
return RISCV_EXCP_ILLEGAL_INST;
}
static RISCVException pmp(CPURISCVState *env, int csrno)
{
- if (riscv_feature(env, RISCV_FEATURE_PMP)) {
+ if (riscv_cpu_cfg(env)->pmp) {
+ if (csrno <= CSR_PMPCFG3) {
+ uint32_t reg_index = csrno - CSR_PMPCFG0;
+
+ /* TODO: RV128 restriction check */
+ if ((reg_index & 1) && (riscv_cpu_mxl(env) == MXL_RV64)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ }
+
return RISCV_EXCP_NONE;
}
static RISCVException epmp(CPURISCVState *env, int csrno)
{
- if (env->priv == PRV_M && riscv_feature(env, RISCV_FEATURE_EPMP)) {
+ if (riscv_cpu_cfg(env)->epmp) {
return RISCV_EXCP_NONE;
}
static RISCVException debug(CPURISCVState *env, int csrno)
{
- if (riscv_feature(env, RISCV_FEATURE_DEBUG)) {
+ if (riscv_cpu_cfg(env)->debug) {
return RISCV_EXCP_NONE;
}
static RISCVException seed(CPURISCVState *env, int csrno)
{
- RISCVCPU *cpu = env_archcpu(env);
-
- if (!cpu->cfg.ext_zkr) {
+ if (!riscv_cpu_cfg(env)->ext_zkr) {
return RISCV_EXCP_ILLEGAL_INST;
}
#if !defined(CONFIG_USER_ONLY)
+ if (env->debugger) {
+ return RISCV_EXCP_NONE;
+ }
+
/*
* With a CSR read-write instruction:
* 1) The seed CSR is always available in machine mode as normal.
*/
if (env->priv == PRV_M) {
return RISCV_EXCP_NONE;
- } else if (riscv_cpu_virt_enabled(env)) {
+ } else if (env->virt_enabled) {
if (env->mseccfg & MSECCFG_SSEED) {
return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
} else {
static int read_vlenb(CPURISCVState *env, int csrno, target_ulong *val)
{
- *val = env_archcpu(env)->cfg.vlen >> 3;
+ *val = riscv_cpu_cfg(env)->vlen >> 3;
return RISCV_EXCP_NONE;
}
* The vstart CSR is defined to have only enough writable bits
* to hold the largest element index, i.e. lg2(VLEN) bits.
*/
- env->vstart = val & ~(~0ULL << ctzl(env_archcpu(env)->cfg.vlen));
+ env->vstart = val & ~(~0ULL << ctzl(riscv_cpu_cfg(env)->vlen));
return RISCV_EXCP_NONE;
}
counter.mhpmcounter_val;
if (get_field(env->mcountinhibit, BIT(ctr_idx))) {
- /**
+ /*
* Counter should not increment if inhibit bit is set. We can't really
* stop the icount counting. Just return the counter value written by
* the supervisor to indicate that counter was not incremented.
}
}
- /**
+ /*
* The kernel computes the perf delta by subtracting the current value from
* the value it initialized previously (ctr_val).
*/
static RISCVException read_time(CPURISCVState *env, int csrno,
target_ulong *val)
{
- uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0;
+ uint64_t delta = env->virt_enabled ? env->htimedelta : 0;
if (!env->rdtime_fn) {
return RISCV_EXCP_ILLEGAL_INST;
static RISCVException read_timeh(CPURISCVState *env, int csrno,
target_ulong *val)
{
- uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0;
+ uint64_t delta = env->virt_enabled ? env->htimedelta : 0;
if (!env->rdtime_fn) {
return RISCV_EXCP_ILLEGAL_INST;
return RISCV_EXCP_NONE;
}
-static RISCVException sstc(CPURISCVState *env, int csrno)
-{
- CPUState *cs = env_cpu(env);
- RISCVCPU *cpu = RISCV_CPU(cs);
- bool hmode_check = false;
-
- 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;
- }
-
- if (riscv_cpu_virt_enabled(env)) {
- if (!(get_field(env->hcounteren, COUNTEREN_TM) &
- get_field(env->henvcfg, HENVCFG_STCE))) {
- return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
- }
- }
-
- if ((csrno == CSR_VSTIMECMP) || (csrno == CSR_VSTIMECMPH)) {
- hmode_check = true;
- }
-
- return hmode_check ? hmode(env, csrno) : 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_vstimecmp(CPURISCVState *env, int csrno,
- target_ulong *val)
+ target_ulong *val)
{
*val = env->vstimecmp;
}
static RISCVException read_vstimecmph(CPURISCVState *env, int csrno,
- target_ulong *val)
+ target_ulong *val)
{
*val = env->vstimecmp >> 32;
}
static RISCVException write_vstimecmp(CPURISCVState *env, int csrno,
- target_ulong val)
+ target_ulong val)
{
- RISCVCPU *cpu = env_archcpu(env);
-
if (riscv_cpu_mxl(env) == MXL_RV32) {
env->vstimecmp = deposit64(env->vstimecmp, 0, 32, (uint64_t)val);
} else {
env->vstimecmp = val;
}
- riscv_timer_write_timecmp(cpu, env->vstimer, env->vstimecmp,
+ riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp,
env->htimedelta, MIP_VSTIP);
return RISCV_EXCP_NONE;
}
static RISCVException write_vstimecmph(CPURISCVState *env, int csrno,
- target_ulong val)
+ target_ulong val)
{
- RISCVCPU *cpu = env_archcpu(env);
-
env->vstimecmp = deposit64(env->vstimecmp, 32, 32, (uint64_t)val);
- riscv_timer_write_timecmp(cpu, env->vstimer, env->vstimecmp,
+ riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp,
env->htimedelta, MIP_VSTIP);
return RISCV_EXCP_NONE;
static RISCVException read_stimecmp(CPURISCVState *env, int csrno,
target_ulong *val)
{
- if (riscv_cpu_virt_enabled(env)) {
+ if (env->virt_enabled) {
*val = env->vstimecmp;
} else {
*val = env->stimecmp;
}
static RISCVException read_stimecmph(CPURISCVState *env, int csrno,
- target_ulong *val)
+ target_ulong *val)
{
- if (riscv_cpu_virt_enabled(env)) {
+ if (env->virt_enabled) {
*val = env->vstimecmp >> 32;
} else {
*val = env->stimecmp >> 32;
}
static RISCVException write_stimecmp(CPURISCVState *env, int csrno,
- target_ulong val)
+ target_ulong val)
{
- RISCVCPU *cpu = env_archcpu(env);
-
- if (riscv_cpu_virt_enabled(env)) {
+ if (env->virt_enabled) {
+ if (env->hvictl & HVICTL_VTI) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
return write_vstimecmp(env, csrno, val);
}
env->stimecmp = val;
}
- riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP);
+ riscv_timer_write_timecmp(env, env->stimer, env->stimecmp, 0, MIP_STIP);
return RISCV_EXCP_NONE;
}
static RISCVException write_stimecmph(CPURISCVState *env, int csrno,
- target_ulong val)
+ target_ulong val)
{
- RISCVCPU *cpu = env_archcpu(env);
-
- if (riscv_cpu_virt_enabled(env)) {
+ if (env->virt_enabled) {
+ if (env->hvictl & HVICTL_VTI) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
return write_vstimecmph(env, csrno, val);
}
env->stimecmp = deposit64(env->stimecmp, 32, 32, (uint64_t)val);
- riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP);
+ riscv_timer_write_timecmp(env, env->stimer, env->stimecmp, 0, MIP_STIP);
return RISCV_EXCP_NONE;
}
static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP |
SIP_LCOFIP;
static const target_ulong hip_writable_mask = MIP_VSSIP;
-static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
+static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP |
+ MIP_VSEIP;
static const target_ulong vsip_writable_mask = MIP_VSSIP;
-static const char valid_vm_1_10_32[16] = {
- [VM_1_10_MBARE] = 1,
- [VM_1_10_SV32] = 1
+const bool valid_vm_1_10_32[16] = {
+ [VM_1_10_MBARE] = true,
+ [VM_1_10_SV32] = true
};
-static const char valid_vm_1_10_64[16] = {
- [VM_1_10_MBARE] = 1,
- [VM_1_10_SV39] = 1,
- [VM_1_10_SV48] = 1,
- [VM_1_10_SV57] = 1
+const bool valid_vm_1_10_64[16] = {
+ [VM_1_10_MBARE] = true,
+ [VM_1_10_SV39] = true,
+ [VM_1_10_SV48] = true,
+ [VM_1_10_SV57] = true
};
/* Machine Information Registers */
static RISCVException read_mvendorid(CPURISCVState *env, int csrno,
target_ulong *val)
{
- CPUState *cs = env_cpu(env);
- RISCVCPU *cpu = RISCV_CPU(cs);
-
- *val = cpu->cfg.mvendorid;
+ *val = riscv_cpu_cfg(env)->mvendorid;
return RISCV_EXCP_NONE;
}
static RISCVException read_marchid(CPURISCVState *env, int csrno,
target_ulong *val)
{
- CPUState *cs = env_cpu(env);
- RISCVCPU *cpu = RISCV_CPU(cs);
-
- *val = cpu->cfg.marchid;
+ *val = riscv_cpu_cfg(env)->marchid;
return RISCV_EXCP_NONE;
}
static RISCVException read_mimpid(CPURISCVState *env, int csrno,
target_ulong *val)
{
- CPUState *cs = env_cpu(env);
- RISCVCPU *cpu = RISCV_CPU(cs);
-
- *val = cpu->cfg.mimpid;
+ *val = riscv_cpu_cfg(env)->mimpid;
return RISCV_EXCP_NONE;
}
return RISCV_EXCP_NONE;
}
-static int validate_vm(CPURISCVState *env, target_ulong vm)
-{
- if (riscv_cpu_mxl(env) == MXL_RV32) {
- return valid_vm_1_10_32[vm & 0xf];
- } else {
- return valid_vm_1_10_64[vm & 0xf];
+static bool validate_vm(CPURISCVState *env, target_ulong vm)
+{
+ return (vm & 0xf) <=
+ satp_mode_max_from_map(riscv_cpu_cfg(env)->satp_mode.map);
+}
+
+static target_ulong legalize_mpp(CPURISCVState *env, target_ulong old_mpp,
+ target_ulong val)
+{
+ bool valid = false;
+ target_ulong new_mpp = get_field(val, MSTATUS_MPP);
+
+ switch (new_mpp) {
+ case PRV_M:
+ valid = true;
+ break;
+ case PRV_S:
+ valid = riscv_has_ext(env, RVS);
+ break;
+ case PRV_U:
+ valid = riscv_has_ext(env, RVU);
+ break;
+ }
+
+ /* Remain field unchanged if new_mpp value is invalid */
+ if (!valid) {
+ val = set_field(val, MSTATUS_MPP, old_mpp);
}
+
+ return val;
}
static RISCVException write_mstatus(CPURISCVState *env, int csrno,
uint64_t mask = 0;
RISCVMXL xl = riscv_cpu_mxl(env);
+ /*
+ * MPP field have been made WARL since priv version 1.11. However,
+ * legalization for it will not break any software running on 1.10.
+ */
+ val = legalize_mpp(env, get_field(mstatus, MSTATUS_MPP), val);
+
/* flush tlb on mstatus fields that affect VM */
- if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | MSTATUS_MPV |
- MSTATUS_MPRV | MSTATUS_SUM)) {
+ if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPV)) {
tlb_flush(env_cpu(env));
}
mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE |
static RISCVException read_mstatus_i128(CPURISCVState *env, int csrno,
Int128 *val)
{
- *val = int128_make128(env->mstatus, add_status_sd(MXL_RV128, env->mstatus));
+ *val = int128_make128(env->mstatus, add_status_sd(MXL_RV128,
+ env->mstatus));
return RISCV_EXCP_NONE;
}
static RISCVException write_misa(CPURISCVState *env, int csrno,
target_ulong val)
{
- if (!riscv_feature(env, RISCV_FEATURE_MISA)) {
+ if (!riscv_cpu_cfg(env)->misa_w) {
/* drop write to misa */
return RISCV_EXCP_NONE;
}
/* 'E' excludes all other extensions */
if (val & RVE) {
- /* when we support 'E' we can do "val = RVE;" however
+ /*
+ * when we support 'E' we can do "val = RVE;" however
* for now we just drop writes if 'E' is present.
*/
return RISCV_EXCP_NONE;
/* Mask extensions that are not supported by this hart */
val &= env->misa_ext_mask;
- /* Mask extensions that are not supported by QEMU */
- val &= (RVI | RVE | RVM | RVA | RVF | RVD | RVC | RVS | RVU | RVV);
-
/* 'D' depends on 'F', so clear 'D' if 'F' is not present */
if ((val & RVD) && !(val & RVF)) {
val &= ~RVD;
}
- /* Suppress 'C' if next instruction is not aligned
+ /*
+ * Suppress 'C' if next instruction is not aligned
* TODO: this should check next_pc
*/
if ((val & RVC) && (GETPC() & ~3) != 0) {
static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno)
{
- if (!riscv_cpu_virt_enabled(env)) {
+ if (!env->virt_enabled) {
return csrno;
}
done:
if (ret) {
- return (riscv_cpu_virt_enabled(env) && virt) ?
+ return (env->virt_enabled && virt) ?
RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST;
}
return RISCV_EXCP_NONE;
done:
if (ret) {
- return (riscv_cpu_virt_enabled(env) && virt) ?
+ return (env->virt_enabled && virt) ?
RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST;
}
return RISCV_EXCP_NONE;
}
static RISCVException read_mepc(CPURISCVState *env, int csrno,
- target_ulong *val)
+ target_ulong *val)
{
*val = env->mepc;
return RISCV_EXCP_NONE;
}
static RISCVException write_mepc(CPURISCVState *env, int csrno,
- target_ulong val)
+ target_ulong val)
{
env->mepc = val;
return RISCV_EXCP_NONE;
}
static RISCVException read_mcause(CPURISCVState *env, int csrno,
- target_ulong *val)
+ target_ulong *val)
{
*val = env->mcause;
return RISCV_EXCP_NONE;
}
static RISCVException write_mcause(CPURISCVState *env, int csrno,
- target_ulong val)
+ target_ulong val)
{
env->mcause = val;
return RISCV_EXCP_NONE;
/* Execution environment configuration setup */
static RISCVException read_menvcfg(CPURISCVState *env, int csrno,
- target_ulong *val)
+ target_ulong *val)
{
*val = env->menvcfg;
return RISCV_EXCP_NONE;
}
static RISCVException write_menvcfg(CPURISCVState *env, int csrno,
- target_ulong val)
+ target_ulong val)
{
+ const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
uint64_t mask = MENVCFG_FIOM | MENVCFG_CBIE | MENVCFG_CBCFE | MENVCFG_CBZE;
if (riscv_cpu_mxl(env) == MXL_RV64) {
- mask |= MENVCFG_PBMTE | MENVCFG_STCE;
+ mask |= (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) |
+ (cfg->ext_sstc ? MENVCFG_STCE : 0) |
+ (cfg->ext_svadu ? MENVCFG_HADE : 0);
}
env->menvcfg = (env->menvcfg & ~mask) | (val & mask);
}
static RISCVException read_menvcfgh(CPURISCVState *env, int csrno,
- target_ulong *val)
+ target_ulong *val)
{
*val = env->menvcfg >> 32;
return RISCV_EXCP_NONE;
}
static RISCVException write_menvcfgh(CPURISCVState *env, int csrno,
- target_ulong val)
+ target_ulong val)
{
- uint64_t mask = MENVCFG_PBMTE | MENVCFG_STCE;
+ const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
+ uint64_t mask = (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) |
+ (cfg->ext_sstc ? MENVCFG_STCE : 0) |
+ (cfg->ext_svadu ? MENVCFG_HADE : 0);
uint64_t valh = (uint64_t)val << 32;
env->menvcfg = (env->menvcfg & ~mask) | (valh & mask);
}
static RISCVException read_senvcfg(CPURISCVState *env, int csrno,
- target_ulong *val)
+ target_ulong *val)
{
+ RISCVException ret;
+
+ ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
*val = env->senvcfg;
return RISCV_EXCP_NONE;
}
static RISCVException write_senvcfg(CPURISCVState *env, int csrno,
- target_ulong val)
+ target_ulong val)
{
uint64_t mask = SENVCFG_FIOM | SENVCFG_CBIE | SENVCFG_CBCFE | SENVCFG_CBZE;
+ RISCVException ret;
- env->senvcfg = (env->senvcfg & ~mask) | (val & mask);
+ ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+ env->senvcfg = (env->senvcfg & ~mask) | (val & mask);
return RISCV_EXCP_NONE;
}
static RISCVException read_henvcfg(CPURISCVState *env, int csrno,
- target_ulong *val)
+ target_ulong *val)
{
- *val = env->henvcfg;
+ RISCVException ret;
+
+ ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
+ /*
+ * henvcfg.pbmte is read_only 0 when menvcfg.pbmte = 0
+ * henvcfg.stce is read_only 0 when menvcfg.stce = 0
+ * henvcfg.hade is read_only 0 when menvcfg.hade = 0
+ */
+ *val = env->henvcfg & (~(HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_HADE) |
+ env->menvcfg);
return RISCV_EXCP_NONE;
}
static RISCVException write_henvcfg(CPURISCVState *env, int csrno,
- target_ulong val)
+ target_ulong val)
{
uint64_t mask = HENVCFG_FIOM | HENVCFG_CBIE | HENVCFG_CBCFE | HENVCFG_CBZE;
+ RISCVException ret;
+
+ ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
if (riscv_cpu_mxl(env) == MXL_RV64) {
- mask |= HENVCFG_PBMTE | HENVCFG_STCE;
+ mask |= env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_HADE);
}
env->henvcfg = (env->henvcfg & ~mask) | (val & mask);
}
static RISCVException read_henvcfgh(CPURISCVState *env, int csrno,
- target_ulong *val)
+ target_ulong *val)
{
- *val = env->henvcfg >> 32;
+ RISCVException ret;
+
+ ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
+ *val = (env->henvcfg & (~(HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_HADE) |
+ env->menvcfg)) >> 32;
return RISCV_EXCP_NONE;
}
static RISCVException write_henvcfgh(CPURISCVState *env, int csrno,
- target_ulong val)
+ target_ulong val)
{
- uint64_t mask = HENVCFG_PBMTE | HENVCFG_STCE;
+ uint64_t mask = env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE |
+ HENVCFG_HADE);
uint64_t valh = (uint64_t)val << 32;
+ RISCVException ret;
+
+ ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
env->henvcfg = (env->henvcfg & ~mask) | (valh & mask);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mstateen(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mstateen[csrno - CSR_MSTATEEN0];
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mstateen(CPURISCVState *env, int csrno,
+ uint64_t wr_mask, target_ulong new_val)
+{
+ uint64_t *reg;
+
+ reg = &env->mstateen[csrno - CSR_MSTATEEN0];
+ *reg = (*reg & ~wr_mask) | (new_val & wr_mask);
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mstateen0(CPURISCVState *env, int csrno,
+ target_ulong new_val)
+{
+ uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
+
+ return write_mstateen(env, csrno, wr_mask, new_val);
+}
+
+static RISCVException write_mstateen_1_3(CPURISCVState *env, int csrno,
+ target_ulong new_val)
+{
+ return write_mstateen(env, csrno, SMSTATEEN_STATEEN, new_val);
+}
+
+static RISCVException read_mstateenh(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mstateen[csrno - CSR_MSTATEEN0H] >> 32;
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mstateenh(CPURISCVState *env, int csrno,
+ uint64_t wr_mask, target_ulong new_val)
+{
+ uint64_t *reg, val;
+
+ reg = &env->mstateen[csrno - CSR_MSTATEEN0H];
+ val = (uint64_t)new_val << 32;
+ val |= *reg & 0xFFFFFFFF;
+ *reg = (*reg & ~wr_mask) | (val & wr_mask);
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mstateen0h(CPURISCVState *env, int csrno,
+ target_ulong new_val)
+{
+ uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
+
+ return write_mstateenh(env, csrno, wr_mask, new_val);
+}
+
+static RISCVException write_mstateenh_1_3(CPURISCVState *env, int csrno,
+ target_ulong new_val)
+{
+ return write_mstateenh(env, csrno, SMSTATEEN_STATEEN, new_val);
+}
+
+static RISCVException read_hstateen(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ int index = csrno - CSR_HSTATEEN0;
+
+ *val = env->hstateen[index] & env->mstateen[index];
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_hstateen(CPURISCVState *env, int csrno,
+ uint64_t mask, target_ulong new_val)
+{
+ int index = csrno - CSR_HSTATEEN0;
+ uint64_t *reg, wr_mask;
+
+ reg = &env->hstateen[index];
+ wr_mask = env->mstateen[index] & mask;
+ *reg = (*reg & ~wr_mask) | (new_val & wr_mask);
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_hstateen0(CPURISCVState *env, int csrno,
+ target_ulong new_val)
+{
+ uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
+
+ return write_hstateen(env, csrno, wr_mask, new_val);
+}
+
+static RISCVException write_hstateen_1_3(CPURISCVState *env, int csrno,
+ target_ulong new_val)
+{
+ return write_hstateen(env, csrno, SMSTATEEN_STATEEN, new_val);
+}
+
+static RISCVException read_hstateenh(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ int index = csrno - CSR_HSTATEEN0H;
+
+ *val = (env->hstateen[index] >> 32) & (env->mstateen[index] >> 32);
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_hstateenh(CPURISCVState *env, int csrno,
+ uint64_t mask, target_ulong new_val)
+{
+ int index = csrno - CSR_HSTATEEN0H;
+ uint64_t *reg, wr_mask, val;
+
+ reg = &env->hstateen[index];
+ val = (uint64_t)new_val << 32;
+ val |= *reg & 0xFFFFFFFF;
+ wr_mask = env->mstateen[index] & mask;
+ *reg = (*reg & ~wr_mask) | (val & wr_mask);
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_hstateen0h(CPURISCVState *env, int csrno,
+ target_ulong new_val)
+{
+ uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
+
+ return write_hstateenh(env, csrno, wr_mask, new_val);
+}
+
+static RISCVException write_hstateenh_1_3(CPURISCVState *env, int csrno,
+ target_ulong new_val)
+{
+ return write_hstateenh(env, csrno, SMSTATEEN_STATEEN, new_val);
+}
+
+static RISCVException read_sstateen(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ bool virt = env->virt_enabled;
+ int index = csrno - CSR_SSTATEEN0;
+
+ *val = env->sstateen[index] & env->mstateen[index];
+ if (virt) {
+ *val &= env->hstateen[index];
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_sstateen(CPURISCVState *env, int csrno,
+ uint64_t mask, target_ulong new_val)
+{
+ bool virt = env->virt_enabled;
+ int index = csrno - CSR_SSTATEEN0;
+ uint64_t wr_mask;
+ uint64_t *reg;
+
+ wr_mask = env->mstateen[index] & mask;
+ if (virt) {
+ wr_mask &= env->hstateen[index];
+ }
+
+ reg = &env->sstateen[index];
+ *reg = (*reg & ~wr_mask) | (new_val & wr_mask);
return RISCV_EXCP_NONE;
}
+static RISCVException write_sstateen0(CPURISCVState *env, int csrno,
+ target_ulong new_val)
+{
+ uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
+
+ return write_sstateen(env, csrno, wr_mask, new_val);
+}
+
+static RISCVException write_sstateen_1_3(CPURISCVState *env, int csrno,
+ target_ulong new_val)
+{
+ return write_sstateen(env, csrno, SMSTATEEN_STATEEN, new_val);
+}
+
static RISCVException rmw_mip64(CPURISCVState *env, int csrno,
uint64_t *ret_val,
uint64_t new_val, uint64_t wr_mask)
{
- RISCVCPU *cpu = env_archcpu(env);
uint64_t old_mip, mask = wr_mask & delegable_ints;
uint32_t gin;
new_val |= env->external_seip * MIP_SEIP;
}
- if (cpu->cfg.ext_sstc && (env->priv == PRV_M) &&
+ if (riscv_cpu_cfg(env)->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));
+ old_mip = riscv_cpu_update_mip(env, mask, (new_val & mask));
} else {
old_mip = env->mip;
}
uint64_t new_val, uint64_t wr_mask)
{
RISCVException ret;
- uint64_t rval, vsbits, mask = env->hideleg & VS_MODE_INTERRUPTS;
+ uint64_t rval, mask = env->hideleg & VS_MODE_INTERRUPTS;
/* Bring VS-level bits to correct position */
- vsbits = new_val & (VS_MODE_INTERRUPTS >> 1);
- new_val &= ~(VS_MODE_INTERRUPTS >> 1);
- new_val |= vsbits << 1;
- vsbits = wr_mask & (VS_MODE_INTERRUPTS >> 1);
- wr_mask &= ~(VS_MODE_INTERRUPTS >> 1);
- wr_mask |= vsbits << 1;
+ new_val = (new_val & (VS_MODE_INTERRUPTS >> 1)) << 1;
+ wr_mask = (wr_mask & (VS_MODE_INTERRUPTS >> 1)) << 1;
ret = rmw_mie64(env, csrno, &rval, new_val, wr_mask & mask);
if (ret_val) {
- rval &= mask;
- vsbits = rval & VS_MODE_INTERRUPTS;
- rval &= ~VS_MODE_INTERRUPTS;
- *ret_val = rval | (vsbits >> 1);
+ *ret_val = (rval & mask) >> 1;
}
return ret;
RISCVException ret;
uint64_t mask = env->mideleg & S_MODE_INTERRUPTS;
- if (riscv_cpu_virt_enabled(env)) {
+ if (env->virt_enabled) {
if (env->hvictl & HVICTL_VTI) {
return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
uint64_t new_val, uint64_t wr_mask)
{
RISCVException ret;
- uint64_t rval, vsbits, mask = env->hideleg & vsip_writable_mask;
+ uint64_t rval, mask = env->hideleg & VS_MODE_INTERRUPTS;
/* Bring VS-level bits to correct position */
- vsbits = new_val & (VS_MODE_INTERRUPTS >> 1);
- new_val &= ~(VS_MODE_INTERRUPTS >> 1);
- new_val |= vsbits << 1;
- vsbits = wr_mask & (VS_MODE_INTERRUPTS >> 1);
- wr_mask &= ~(VS_MODE_INTERRUPTS >> 1);
- wr_mask |= vsbits << 1;
-
- ret = rmw_mip64(env, csrno, &rval, new_val, wr_mask & mask);
+ new_val = (new_val & (VS_MODE_INTERRUPTS >> 1)) << 1;
+ wr_mask = (wr_mask & (VS_MODE_INTERRUPTS >> 1)) << 1;
+
+ ret = rmw_mip64(env, csrno, &rval, new_val,
+ wr_mask & mask & vsip_writable_mask);
if (ret_val) {
- rval &= mask;
- vsbits = rval & VS_MODE_INTERRUPTS;
- rval &= ~VS_MODE_INTERRUPTS;
- *ret_val = rval | (vsbits >> 1);
+ *ret_val = (rval & mask) >> 1;
}
return ret;
RISCVException ret;
uint64_t mask = env->mideleg & sip_writable_mask;
- if (riscv_cpu_virt_enabled(env)) {
+ if (env->virt_enabled) {
if (env->hvictl & HVICTL_VTI) {
return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
static RISCVException read_satp(CPURISCVState *env, int csrno,
target_ulong *val)
{
- if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
+ if (!riscv_cpu_cfg(env)->mmu) {
*val = 0;
return RISCV_EXCP_NONE;
}
-
- if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
- return RISCV_EXCP_ILLEGAL_INST;
- } else {
- *val = env->satp;
- }
-
+ *val = env->satp;
return RISCV_EXCP_NONE;
}
static RISCVException write_satp(CPURISCVState *env, int csrno,
target_ulong val)
{
- target_ulong vm, mask;
+ target_ulong mask;
+ bool vm;
- if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
+ if (!riscv_cpu_cfg(env)->mmu) {
return RISCV_EXCP_NONE;
}
}
if (vm && mask) {
- if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
- return RISCV_EXCP_ILLEGAL_INST;
- } else {
- /*
- * The ISA defines SATP.MODE=Bare as "no translation", but we still
- * pass these through QEMU's TLB emulation as it improves
- * performance. Flushing the TLB on SATP writes with paging
- * enabled avoids leaking those invalid cached mappings.
- */
- tlb_flush(env_cpu(env));
- env->satp = val;
- }
+ /*
+ * The ISA defines SATP.MODE=Bare as "no translation", but we still
+ * pass these through QEMU's TLB emulation as it improves
+ * performance. Flushing the TLB on SATP writes with paging
+ * enabled avoids leaking those invalid cached mappings.
+ */
+ tlb_flush(env_cpu(env));
+ env->satp = val;
}
return RISCV_EXCP_NONE;
}
int irq;
uint8_t iprio;
- if (riscv_cpu_virt_enabled(env)) {
+ if (env->virt_enabled) {
return read_vstopi(env, CSR_VSTOPI, val);
}
{
env->hstatus = val;
if (riscv_cpu_mxl(env) != MXL_RV32 && get_field(val, HSTATUS_VSXL) != 2) {
- qemu_log_mask(LOG_UNIMP, "QEMU does not support mixed HSXLEN options.");
+ qemu_log_mask(LOG_UNIMP,
+ "QEMU does not support mixed HSXLEN options.");
}
if (get_field(val, HSTATUS_VSBE) != 0) {
qemu_log_mask(LOG_UNIMP, "QEMU does not support big endian guests.");
val &= ((((target_ulong)1) << env->geilen) - 1) << 1;
env->hgeie = val;
/* Update mip.SGEIP bit */
- riscv_cpu_update_mip(env_archcpu(env), MIP_SGEIP,
+ riscv_cpu_update_mip(env, MIP_SGEIP,
BOOL_TO_MASK(!!(env->hgeie & env->hgeip)));
return RISCV_EXCP_NONE;
}
} else {
env->htimedelta = val;
}
+
+ if (riscv_cpu_cfg(env)->ext_sstc && env->rdtime_fn) {
+ riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp,
+ env->htimedelta, MIP_VSTIP);
+ }
+
return RISCV_EXCP_NONE;
}
}
env->htimedelta = deposit64(env->htimedelta, 32, 32, (uint64_t)val);
+
+ if (riscv_cpu_cfg(env)->ext_sstc && env->rdtime_fn) {
+ riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp,
+ env->htimedelta, MIP_VSTIP);
+ }
+
return RISCV_EXCP_NONE;
}
/* First index has to be a multiple of number of irqs per register */
if (first_index % num_irqs) {
- return (riscv_cpu_virt_enabled(env)) ?
+ return (env->virt_enabled) ?
RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST;
}
/* First index has to be a multiple of number of irqs per register */
if (first_index % num_irqs) {
- return (riscv_cpu_virt_enabled(env)) ?
+ return (env->virt_enabled) ?
RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST;
}
}
static RISCVException write_mseccfg(CPURISCVState *env, int csrno,
- target_ulong val)
+ target_ulong val)
{
mseccfg_csr_write(env, val);
return RISCV_EXCP_NONE;
}
-static bool check_pmp_reg_index(CPURISCVState *env, uint32_t reg_index)
-{
- /* TODO: RV128 restriction check */
- if ((reg_index & 1) && (riscv_cpu_mxl(env) == MXL_RV64)) {
- return false;
- }
- return true;
-}
-
static RISCVException read_pmpcfg(CPURISCVState *env, int csrno,
target_ulong *val)
{
uint32_t reg_index = csrno - CSR_PMPCFG0;
- if (!check_pmp_reg_index(env, reg_index)) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
- *val = pmpcfg_csr_read(env, csrno - CSR_PMPCFG0);
+ *val = pmpcfg_csr_read(env, reg_index);
return RISCV_EXCP_NONE;
}
{
uint32_t reg_index = csrno - CSR_PMPCFG0;
- if (!check_pmp_reg_index(env, reg_index)) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
- pmpcfg_csr_write(env, csrno - CSR_PMPCFG0, val);
+ pmpcfg_csr_write(env, reg_index, val);
return RISCV_EXCP_NONE;
}
return RISCV_EXCP_NONE;
}
+static RISCVException read_tinfo(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = tinfo_csr_read(env);
+ return RISCV_EXCP_NONE;
+}
+
/*
* Functions to access Pointer Masking feature registers
* We have to check if current priv lvl could modify
target_ulong wpri_val = val & MMTE_MASK;
if (val != wpri_val) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s" TARGET_FMT_lx "\n",
- "MMTE: WPRI violation written 0x", val,
- "vs expected 0x", wpri_val);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s"
+ TARGET_FMT_lx "\n", "MMTE: WPRI violation written 0x",
+ val, "vs expected 0x", wpri_val);
}
/* for machine mode pm.current is hardwired to 1 */
wpri_val |= MMTE_M_PM_CURRENT;
/* hardwiring pm.instruction bit to 0, since it's not supported yet */
wpri_val &= ~(MMTE_M_PM_INSN | MMTE_S_PM_INSN | MMTE_U_PM_INSN);
- env->mmte = wpri_val | PM_EXT_DIRTY;
+ env->mmte = wpri_val | EXT_STATUS_DIRTY;
riscv_cpu_update_mask(env);
/* Set XS and SD bits, since PM CSRs are dirty */
target_ulong wpri_val = val & SMTE_MASK;
if (val != wpri_val) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s" TARGET_FMT_lx "\n",
- "SMTE: WPRI violation written 0x", val,
- "vs expected 0x", wpri_val);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s"
+ TARGET_FMT_lx "\n", "SMTE: WPRI violation written 0x",
+ val, "vs expected 0x", wpri_val);
}
/* if pm.current==0 we can't modify current PM CSRs */
target_ulong wpri_val = val & UMTE_MASK;
if (val != wpri_val) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s" TARGET_FMT_lx "\n",
- "UMTE: WPRI violation written 0x", val,
- "vs expected 0x", wpri_val);
+ qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s"
+ TARGET_FMT_lx "\n", "UMTE: WPRI violation written 0x",
+ val, "vs expected 0x", wpri_val);
}
if (check_pm_current_disabled(env, csrno)) {
if ((env->priv == PRV_M) && (env->mmte & M_PM_ENABLE)) {
env->cur_pmmask = val;
}
- env->mmte |= PM_EXT_DIRTY;
+ env->mmte |= EXT_STATUS_DIRTY;
/* Set XS and SD bits, since PM CSRs are dirty */
mstatus = env->mstatus | MSTATUS_XS;
if ((env->priv == PRV_S) && (env->mmte & S_PM_ENABLE)) {
env->cur_pmmask = val;
}
- env->mmte |= PM_EXT_DIRTY;
+ env->mmte |= EXT_STATUS_DIRTY;
/* Set XS and SD bits, since PM CSRs are dirty */
mstatus = env->mstatus | MSTATUS_XS;
if ((env->priv == PRV_U) && (env->mmte & U_PM_ENABLE)) {
env->cur_pmmask = val;
}
- env->mmte |= PM_EXT_DIRTY;
+ env->mmte |= EXT_STATUS_DIRTY;
/* Set XS and SD bits, since PM CSRs are dirty */
mstatus = env->mstatus | MSTATUS_XS;
if ((env->priv == PRV_M) && (env->mmte & M_PM_ENABLE)) {
env->cur_pmbase = val;
}
- env->mmte |= PM_EXT_DIRTY;
+ env->mmte |= EXT_STATUS_DIRTY;
/* Set XS and SD bits, since PM CSRs are dirty */
mstatus = env->mstatus | MSTATUS_XS;
if ((env->priv == PRV_S) && (env->mmte & S_PM_ENABLE)) {
env->cur_pmbase = val;
}
- env->mmte |= PM_EXT_DIRTY;
+ env->mmte |= EXT_STATUS_DIRTY;
/* Set XS and SD bits, since PM CSRs are dirty */
mstatus = env->mstatus | MSTATUS_XS;
if ((env->priv == PRV_U) && (env->mmte & U_PM_ENABLE)) {
env->cur_pmbase = val;
}
- env->mmte |= PM_EXT_DIRTY;
+ env->mmte |= EXT_STATUS_DIRTY;
/* Set XS and SD bits, since PM CSRs are dirty */
mstatus = env->mstatus | MSTATUS_XS;
static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
int csrno,
- bool write_mask,
- RISCVCPU *cpu)
+ bool write_mask)
{
/* check privileges and return RISCV_EXCP_ILLEGAL_INST if check fails */
- int read_only = get_field(csrno, 0xC00) == 3;
+ bool read_only = get_field(csrno, 0xC00) == 3;
int csr_min_priv = csr_ops[csrno].min_priv_ver;
- /* ensure the CSR extension is enabled. */
- if (!cpu->cfg.ext_icsr) {
+ /* ensure the CSR extension is enabled */
+ if (!riscv_cpu_cfg(env)->ext_icsr) {
return RISCV_EXCP_ILLEGAL_INST;
}
+ /* privileged spec version check */
if (env->priv_ver < csr_min_priv) {
return RISCV_EXCP_ILLEGAL_INST;
}
- /* check predicate */
- if (!csr_ops[csrno].predicate) {
- return RISCV_EXCP_ILLEGAL_INST;
- }
-
+ /* read / write check */
if (write_mask && read_only) {
return RISCV_EXCP_ILLEGAL_INST;
}
+ /*
+ * The predicate() not only does existence check but also does some
+ * access control check which triggers for example virtual instruction
+ * exception in some cases. When writing read-only CSRs in those cases
+ * illegal instruction exception should be triggered instead of virtual
+ * instruction exception. Hence this comes after the read / write check.
+ */
+ g_assert(csr_ops[csrno].predicate != NULL);
RISCVException ret = csr_ops[csrno].predicate(env, csrno);
if (ret != RISCV_EXCP_NONE) {
return ret;
int csr_priv, effective_priv = env->priv;
if (riscv_has_ext(env, RVH) && env->priv == PRV_S &&
- !riscv_cpu_virt_enabled(env)) {
+ !env->virt_enabled) {
/*
* We are in HS mode. Add 1 to the effective privledge level to
* allow us to access the Hypervisor CSRs.
csr_priv = get_field(csrno, 0x300);
if (!env->debugger && (effective_priv < csr_priv)) {
- if (csr_priv == (PRV_S + 1) && riscv_cpu_virt_enabled(env)) {
+ if (csr_priv == (PRV_S + 1) && env->virt_enabled) {
return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
return RISCV_EXCP_ILLEGAL_INST;
target_ulong *ret_value,
target_ulong new_value, target_ulong write_mask)
{
- RISCVCPU *cpu = env_archcpu(env);
-
- RISCVException ret = riscv_csrrw_check(env, csrno, write_mask, cpu);
+ RISCVException ret = riscv_csrrw_check(env, csrno, write_mask);
if (ret != RISCV_EXCP_NONE) {
return ret;
}
Int128 new_value, Int128 write_mask)
{
RISCVException ret;
- RISCVCPU *cpu = env_archcpu(env);
- ret = riscv_csrrw_check(env, csrno, int128_nz(write_mask), cpu);
+ ret = riscv_csrrw_check(env, csrno, int128_nz(write_mask));
if (ret != RISCV_EXCP_NONE) {
return ret;
}
* Fall back to 64-bit version for now, if the 128-bit alternative isn't
* at all defined.
* Note, some CSRs don't need to extend to MXLEN (64 upper bits non
- * significant), for those, this fallback is correctly handling the accesses
+ * significant), for those, this fallback is correctly handling the
+ * accesses
*/
target_ulong old_value;
ret = riscv_csrrw_do64(env, csrno, &old_value,
return ret;
}
+static RISCVException read_jvt(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->jvt;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_jvt(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ env->jvt = val;
+ return RISCV_EXCP_NONE;
+}
+
/* Control and Status Register function table */
riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
/* User Floating-Point CSRs */
[CSR_FRM] = { "frm", fs, read_frm, write_frm },
[CSR_FCSR] = { "fcsr", fs, read_fcsr, write_fcsr },
/* Vector CSRs */
- [CSR_VSTART] = { "vstart", vs, read_vstart, write_vstart,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VCSR] = { "vcsr", vs, read_vcsr, write_vcsr,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VL] = { "vl", vs, read_vl,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VTYPE] = { "vtype", vs, read_vtype,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_VLENB] = { "vlenb", vs, read_vlenb,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VSTART] = { "vstart", vs, read_vstart, write_vstart },
+ [CSR_VXSAT] = { "vxsat", vs, read_vxsat, write_vxsat },
+ [CSR_VXRM] = { "vxrm", vs, read_vxrm, write_vxrm },
+ [CSR_VCSR] = { "vcsr", vs, read_vcsr, write_vcsr },
+ [CSR_VL] = { "vl", vs, read_vl },
+ [CSR_VTYPE] = { "vtype", vs, read_vtype },
+ [CSR_VLENB] = { "vlenb", vs, read_vlenb },
/* User Timers and Counters */
[CSR_CYCLE] = { "cycle", ctr, read_hpmcounter },
[CSR_INSTRET] = { "instret", ctr, read_hpmcounter },
/* Crypto Extension */
[CSR_SEED] = { "seed", seed, NULL, NULL, rmw_seed },
+ /* Zcmt Extension */
+ [CSR_JVT] = {"jvt", zcmt, read_jvt, write_jvt},
+
#if !defined(CONFIG_USER_ONLY)
/* Machine Timers and Counters */
[CSR_MCYCLE] = { "mcycle", any, read_hpmcounter,
[CSR_HENVCFGH] = { "henvcfgh", hmode32, read_henvcfgh, write_henvcfgh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
+ /* Smstateen extension CSRs */
+ [CSR_MSTATEEN0] = { "mstateen0", mstateen, read_mstateen, write_mstateen0,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MSTATEEN0H] = { "mstateen0h", mstateen, read_mstateenh,
+ write_mstateen0h,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MSTATEEN1] = { "mstateen1", mstateen, read_mstateen,
+ write_mstateen_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MSTATEEN1H] = { "mstateen1h", mstateen, read_mstateenh,
+ write_mstateenh_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MSTATEEN2] = { "mstateen2", mstateen, read_mstateen,
+ write_mstateen_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MSTATEEN2H] = { "mstateen2h", mstateen, read_mstateenh,
+ write_mstateenh_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MSTATEEN3] = { "mstateen3", mstateen, read_mstateen,
+ write_mstateen_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MSTATEEN3H] = { "mstateen3h", mstateen, read_mstateenh,
+ write_mstateenh_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HSTATEEN0] = { "hstateen0", hstateen, read_hstateen, write_hstateen0,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HSTATEEN0H] = { "hstateen0h", hstateenh, read_hstateenh,
+ write_hstateen0h,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HSTATEEN1] = { "hstateen1", hstateen, read_hstateen,
+ write_hstateen_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HSTATEEN1H] = { "hstateen1h", hstateenh, read_hstateenh,
+ write_hstateenh_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HSTATEEN2] = { "hstateen2", hstateen, read_hstateen,
+ write_hstateen_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HSTATEEN2H] = { "hstateen2h", hstateenh, read_hstateenh,
+ write_hstateenh_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HSTATEEN3] = { "hstateen3", hstateen, read_hstateen,
+ write_hstateen_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_HSTATEEN3H] = { "hstateen3h", hstateenh, read_hstateenh,
+ write_hstateenh_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_SSTATEEN0] = { "sstateen0", sstateen, read_sstateen, write_sstateen0,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_SSTATEEN1] = { "sstateen1", sstateen, read_sstateen,
+ write_sstateen_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_SSTATEEN2] = { "sstateen2", sstateen, read_sstateen,
+ write_sstateen_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_SSTATEEN3] = { "sstateen3", sstateen, read_sstateen,
+ write_sstateen_1_3,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+
/* Supervisor Trap Setup */
[CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus,
- NULL, read_sstatus_i128 },
- [CSR_SIE] = { "sie", smode, NULL, NULL, rmw_sie },
- [CSR_STVEC] = { "stvec", smode, read_stvec, write_stvec },
+ NULL, read_sstatus_i128 },
+ [CSR_SIE] = { "sie", smode, NULL, NULL, rmw_sie },
+ [CSR_STVEC] = { "stvec", smode, read_stvec, write_stvec },
[CSR_SCOUNTEREN] = { "scounteren", smode, read_scounteren,
- write_scounteren },
+ write_scounteren },
/* Supervisor Trap Handling */
[CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch,
.min_priv_ver = PRIV_VERSION_1_12_0 },
/* Supervisor Protection and Translation */
- [CSR_SATP] = { "satp", smode, read_satp, write_satp },
+ [CSR_SATP] = { "satp", satp, read_satp, write_satp },
/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
[CSR_SISELECT] = { "siselect", aia_smode, NULL, NULL, rmw_xiselect },
.min_priv_ver = PRIV_VERSION_1_12_0 },
[CSR_HGEIP] = { "hgeip", hmode, read_hgeip,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_HGATP] = { "hgatp", hmode, read_hgatp, write_hgatp,
+ [CSR_HGATP] = { "hgatp", hgatp, read_hgatp, write_hgatp,
.min_priv_ver = PRIV_VERSION_1_12_0 },
[CSR_HTIMEDELTA] = { "htimedelta", hmode, read_htimedelta,
write_htimedelta,
[CSR_TDATA1] = { "tdata1", debug, read_tdata, write_tdata },
[CSR_TDATA2] = { "tdata2", debug, read_tdata, write_tdata },
[CSR_TDATA3] = { "tdata3", debug, read_tdata, write_tdata },
+ [CSR_TINFO] = { "tinfo", debug, read_tinfo, write_ignore },
/* User Pointer Masking */
[CSR_UMTE] = { "umte", pointer_masking, read_umte, write_umte },