diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 8a63523851..451261ce5a 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -132,6 +132,7 @@ DEF_HELPER_6(csrrw_i128, tl, env, int, tl, tl, tl, tl) DEF_HELPER_1(sret, tl, env) DEF_HELPER_1(mret, tl, env) DEF_HELPER_1(wfi, void, env) +DEF_HELPER_1(wrs_nto, void, env) DEF_HELPER_1(tlb_flush, void, env) DEF_HELPER_1(tlb_flush_all, void, env) /* Native Debug */ diff --git a/target/riscv/insn_trans/trans_rvzawrs.c.inc b/target/riscv/insn_trans/trans_rvzawrs.c.inc index 32efbff4d5..0eef033838 100644 --- a/target/riscv/insn_trans/trans_rvzawrs.c.inc +++ b/target/riscv/insn_trans/trans_rvzawrs.c.inc @@ -16,7 +16,7 @@ * this program. If not, see . */ -static bool trans_wrs(DisasContext *ctx) +static bool trans_wrs_sto(DisasContext *ctx, arg_wrs_sto *a) { if (!ctx->cfg_ptr->ext_zawrs) { return false; @@ -40,12 +40,23 @@ static bool trans_wrs(DisasContext *ctx) return true; } -#define GEN_TRANS_WRS(insn) \ -static bool trans_ ## insn(DisasContext *ctx, arg_ ## insn *a) \ -{ \ - (void)a; \ - return trans_wrs(ctx); \ -} +static bool trans_wrs_nto(DisasContext *ctx, arg_wrs_nto *a) +{ + if (!ctx->cfg_ptr->ext_zawrs) { + return false; + } -GEN_TRANS_WRS(wrs_nto) -GEN_TRANS_WRS(wrs_sto) + /* + * Depending on the mode of execution, mstatus.TW and hstatus.VTW, wrs.nto + * should raise an exception when the implementation-specific bounded time + * limit has expired. Our time limit is zero, so we either return + * immediately, as does our implementation of wrs.sto, or raise an + * exception, as handled by the wrs.nto helper. + */ +#ifndef CONFIG_USER_ONLY + gen_helper_wrs_nto(tcg_env); +#endif + + /* We only get here when helper_wrs_nto() doesn't raise an exception. */ + return trans_wrs_sto(ctx, NULL); +} diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index f414aaebdb..2baf5bc3ca 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -380,6 +380,17 @@ void helper_wfi(CPURISCVState *env) } } +void helper_wrs_nto(CPURISCVState *env) +{ + if (env->virt_enabled && (env->priv == PRV_S || env->priv == PRV_U) && + get_field(env->hstatus, HSTATUS_VTW) && + !get_field(env->mstatus, MSTATUS_TW)) { + riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC()); + } else if (env->priv != PRV_M && get_field(env->mstatus, MSTATUS_TW)) { + riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); + } +} + void helper_tlb_flush(CPURISCVState *env) { CPUState *cs = env_cpu(env);