Message ID | 20230406072555.21927-3-liweiwei@iscas.ac.cn (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | target/riscv: Fix mstatus.MPP related support | expand |
On 4/6/23 00:25, Weiwei Li wrote: > void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) > { > - if (newpriv > PRV_M) { > + if (newpriv > PRV_M || newpriv == PRV_H) { > g_assert_not_reached(); > } Nit: if (test) { assert_not_reached } -> assert(!test). which emits a more helpful error message before abort. r~
On 4/6/23 00:25, Weiwei Li wrote: > +static target_ulong legalize_mpp(CPURISCVState *env, target_ulong old_mpp, > + target_ulong val) > +{ > + target_ulong new_mpp = get_field(val, MSTATUS_MPP); > + bool mpp_invalid = (new_mpp == PRV_S && !riscv_has_ext(env, RVS)) || > + (new_mpp == PRV_U && !riscv_has_ext(env, RVU)) || > + (new_mpp == PRV_H); > + > + /* Remain field unchanged if new_mpp value is invalid */ > + return mpp_invalid ? set_field(val, MSTATUS_MPP, old_mpp) : val; > +} Does anyone find PRV_H confusing, since that's not what it is? I think it would be nice to remove it entirely. This function might be better as bool valid = false; 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; } if (!valid) { val = set_field(...); } return val; r~
On 2023/4/7 03:28, Richard Henderson wrote: > On 4/6/23 00:25, Weiwei Li wrote: >> void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) >> { >> - if (newpriv > PRV_M) { >> + if (newpriv > PRV_M || newpriv == PRV_H) { >> g_assert_not_reached(); >> } > > Nit: if (test) { assert_not_reached } -> assert(!test). > > which emits a more helpful error message before abort. > OK. I'll update this. Regards, Weiwei Li > > r~
On 2023/4/7 03:33, Richard Henderson wrote: > On 4/6/23 00:25, Weiwei Li wrote: >> +static target_ulong legalize_mpp(CPURISCVState *env, target_ulong >> old_mpp, >> + target_ulong val) >> +{ >> + target_ulong new_mpp = get_field(val, MSTATUS_MPP); >> + bool mpp_invalid = (new_mpp == PRV_S && !riscv_has_ext(env, >> RVS)) || >> + (new_mpp == PRV_U && !riscv_has_ext(env, >> RVU)) || >> + (new_mpp == PRV_H); >> + >> + /* Remain field unchanged if new_mpp value is invalid */ >> + return mpp_invalid ? set_field(val, MSTATUS_MPP, old_mpp) : val; >> +} > > Does anyone find PRV_H confusing, since that's not what it is? > I think it would be nice to remove it entirely. I agree. Maybe PRV_RESERVED is more readable in some cases. > > This function might be better as > > bool valid = false; > > 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; > } > if (!valid) { > val = set_field(...); > } > return val; > > OK. This is more readable. I'll update this. Regards, Weiwei Li > r~
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 2310c7905f..6148f221c3 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -647,12 +647,9 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv, void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) { - if (newpriv > PRV_M) { + if (newpriv > PRV_M || newpriv == PRV_H) { g_assert_not_reached(); } - if (newpriv == PRV_H) { - newpriv = PRV_U; - } if (icount_enabled() && newpriv != env->priv) { riscv_itrigger_update_priv(env); } diff --git a/target/riscv/csr.c b/target/riscv/csr.c index e0b871f6dc..f3ae726853 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1230,6 +1230,18 @@ static bool validate_vm(CPURISCVState *env, target_ulong vm) 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) +{ + target_ulong new_mpp = get_field(val, MSTATUS_MPP); + bool mpp_invalid = (new_mpp == PRV_S && !riscv_has_ext(env, RVS)) || + (new_mpp == PRV_U && !riscv_has_ext(env, RVU)) || + (new_mpp == PRV_H); + + /* Remain field unchanged if new_mpp value is invalid */ + return mpp_invalid ? set_field(val, MSTATUS_MPP, old_mpp) : val; +} + static RISCVException write_mstatus(CPURISCVState *env, int csrno, target_ulong val) { @@ -1237,6 +1249,12 @@ 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)) {