@@ -1022,6 +1022,10 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
riscv_trigger_reset_hold(env);
}
+ if (riscv_cpu_cfg(env)->ext_smwg && env->wg_reset) {
+ env->wg_reset(env);
+ }
+
if (kvm_enabled()) {
kvm_riscv_reset_vcpu(cpu);
}
@@ -432,6 +432,11 @@ struct CPUArchState {
uint64_t kvm_timer_frequency;
#endif /* CONFIG_KVM */
+ /* RISC-V WorldGuard */
+ target_ulong mlwid;
+ target_ulong slwid;
+ target_ulong mwiddeleg;
+
/* machine specific WorldGuard callback */
void (*wg_reset)(CPURISCVState *env);
void (*wid_to_mem_attrs)(MemTxAttrs *attrs, uint32_t wid);
@@ -4264,6 +4264,109 @@ static RISCVException write_upmbase(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
+/* RISC-V Worldguard */
+static RISCVException worldguard_umode(CPURISCVState *env, int csrno)
+{
+ if (!riscv_cpu_cfg(env)->ext_smwg) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return umode(env, csrno);
+}
+
+static RISCVException worldguard_sumode(CPURISCVState *env, int csrno)
+{
+ RISCVException ret;
+
+ if (!riscv_cpu_cfg(env)->ext_sswg) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ ret = smode(env, csrno);
+
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
+ return umode(env, csrno);
+}
+
+static RISCVException rmw_mlwid(CPURISCVState *env, int csrno,
+ target_ulong *ret_val,
+ target_ulong new_val, target_ulong wr_mask)
+{
+ CPUState *cs = env_cpu(env);
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ target_ulong new_mlwid = (env->mlwid & ~wr_mask) | (new_val & wr_mask);
+
+ if (ret_val) {
+ *ret_val = env->mlwid;
+ }
+
+ g_assert(cpu->cfg.mwidlist);
+ if (!(BIT(new_mlwid) & cpu->cfg.mwidlist)) {
+ /* Set WID to lowest legal value if writing illegal value (WARL) */
+ new_mlwid = find_first_bit((unsigned long *)&cpu->cfg.mwidlist, 32);
+ }
+
+ if (env->mlwid != new_mlwid) {
+ env->mlwid = new_mlwid;
+ tlb_flush(cs);
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException rmw_slwid(CPURISCVState *env, int csrno,
+ target_ulong *ret_val,
+ target_ulong new_val, target_ulong wr_mask)
+{
+ target_ulong new_slwid = (env->slwid & ~wr_mask) | (new_val & wr_mask);
+
+ if (!env->mwiddeleg) {
+ /*
+ * When mwiddeleg CSR is zero, access to slwid raises an illegal
+ * instruction exception.
+ */
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ if (ret_val) {
+ *ret_val = env->slwid;
+ }
+
+ if (!(BIT(new_slwid) & env->mwiddeleg)) {
+ /* Set WID to lowest legal value if writing illegal value (WARL) */
+ new_slwid = find_first_bit(
+ (unsigned long *)&env->mwiddeleg, TARGET_LONG_BITS);
+ }
+
+ if (env->slwid != new_slwid) {
+ env->slwid = new_slwid;
+ tlb_flush(env_cpu(env));
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException rmw_mwiddeleg(CPURISCVState *env, int csrno,
+ target_ulong *ret_val,
+ target_ulong new_val, target_ulong wr_mask)
+{
+ CPUState *cs = env_cpu(env);
+ RISCVCPU *cpu = RISCV_CPU(cs);
+
+ if (ret_val) {
+ *ret_val = env->mwiddeleg;
+ }
+
+ env->mwiddeleg = (env->mwiddeleg & ~wr_mask) | (new_val & wr_mask);
+
+ /* Core wgMarker can only have WID value in mwidlist. */
+ env->mwiddeleg &= cpu->cfg.mwidlist;
+
+ return RISCV_EXCP_NONE;
+}
#endif
/* Crypto Extension */
@@ -5230,5 +5333,9 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_SCOUNTOVF] = { "scountovf", sscofpmf, read_scountovf,
.min_priv_ver = PRIV_VERSION_1_12_0 },
+ /* RISC-V WorldGuard */
+ [CSR_MLWID] = { "mlwid", worldguard_umode, NULL, NULL, rmw_mlwid },
+ [CSR_SLWID] = { "slwid", worldguard_sumode, NULL, NULL, rmw_slwid },
+ [CSR_MWIDDELEG] = { "mwiddeleg", worldguard_sumode, NULL, NULL, rmw_mwiddeleg },
#endif /* !CONFIG_USER_ONLY */
};
The WG v0.4 specification adds 3 CSRs to configure S/U/HS/VS-mode WIDs of CPUs in the higher privileged modes. The Smwg extension at least requires a RISC-V HART to have M/U-mode, and the Sswg/Smwgd extension at least requires a RISC-V HART to have M/S/U-mode. Signed-off-by: Jim Shu <jim.shu@sifive.com> --- target/riscv/cpu.c | 4 ++ target/riscv/cpu.h | 5 +++ target/riscv/csr.c | 107 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+)