target/riscv: Implement Ssdbltrp sret, mret and mnret behavior
When the Ssdbltrp extension is enabled, SSTATUS.SDT field is cleared when executing sret. When executing mret/mnret, SSTATUS.SDT is cleared when returning to U, VS or VU and VSSTATUS.SDT is cleared when returning to VU from HS. Signed-off-by: Clément Léger <cleger@rivosinc.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250110125441.3208676-4-cleger@rivosinc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
parent
0aadf8162a
commit
72d71d8732
@ -294,6 +294,18 @@ target_ulong helper_sret(CPURISCVState *env)
|
|||||||
get_field(mstatus, MSTATUS_SPIE));
|
get_field(mstatus, MSTATUS_SPIE));
|
||||||
mstatus = set_field(mstatus, MSTATUS_SPIE, 1);
|
mstatus = set_field(mstatus, MSTATUS_SPIE, 1);
|
||||||
mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
|
mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
|
||||||
|
|
||||||
|
if (riscv_cpu_cfg(env)->ext_ssdbltrp) {
|
||||||
|
if (riscv_has_ext(env, RVH)) {
|
||||||
|
target_ulong prev_vu = get_field(env->hstatus, HSTATUS_SPV) &&
|
||||||
|
prev_priv == PRV_U;
|
||||||
|
/* Returning to VU from HS, vsstatus.sdt = 0 */
|
||||||
|
if (!env->virt_enabled && prev_vu) {
|
||||||
|
env->vsstatus = set_field(env->vsstatus, MSTATUS_SDT, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mstatus = set_field(mstatus, MSTATUS_SDT, 0);
|
||||||
|
}
|
||||||
if (env->priv_ver >= PRIV_VERSION_1_12_0) {
|
if (env->priv_ver >= PRIV_VERSION_1_12_0) {
|
||||||
mstatus = set_field(mstatus, MSTATUS_MPRV, 0);
|
mstatus = set_field(mstatus, MSTATUS_MPRV, 0);
|
||||||
}
|
}
|
||||||
@ -304,7 +316,6 @@ target_ulong helper_sret(CPURISCVState *env)
|
|||||||
target_ulong hstatus = env->hstatus;
|
target_ulong hstatus = env->hstatus;
|
||||||
|
|
||||||
prev_virt = get_field(hstatus, HSTATUS_SPV);
|
prev_virt = get_field(hstatus, HSTATUS_SPV);
|
||||||
|
|
||||||
hstatus = set_field(hstatus, HSTATUS_SPV, 0);
|
hstatus = set_field(hstatus, HSTATUS_SPV, 0);
|
||||||
|
|
||||||
env->hstatus = hstatus;
|
env->hstatus = hstatus;
|
||||||
@ -344,6 +355,22 @@ static void check_ret_from_m_mode(CPURISCVState *env, target_ulong retpc,
|
|||||||
riscv_raise_exception(env, RISCV_EXCP_INST_ACCESS_FAULT, GETPC());
|
riscv_raise_exception(env, RISCV_EXCP_INST_ACCESS_FAULT, GETPC());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static target_ulong ssdbltrp_mxret(CPURISCVState *env, target_ulong mstatus,
|
||||||
|
target_ulong prev_priv,
|
||||||
|
target_ulong prev_virt)
|
||||||
|
{
|
||||||
|
/* If returning to U, VS or VU, sstatus.sdt = 0 */
|
||||||
|
if (prev_priv == PRV_U || (prev_virt &&
|
||||||
|
(prev_priv == PRV_S || prev_priv == PRV_U))) {
|
||||||
|
mstatus = set_field(mstatus, MSTATUS_SDT, 0);
|
||||||
|
/* If returning to VU, vsstatus.sdt = 0 */
|
||||||
|
if (prev_virt && prev_priv == PRV_U) {
|
||||||
|
env->vsstatus = set_field(env->vsstatus, MSTATUS_SDT, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mstatus;
|
||||||
|
}
|
||||||
|
|
||||||
target_ulong helper_mret(CPURISCVState *env)
|
target_ulong helper_mret(CPURISCVState *env)
|
||||||
{
|
{
|
||||||
@ -361,6 +388,9 @@ target_ulong helper_mret(CPURISCVState *env)
|
|||||||
mstatus = set_field(mstatus, MSTATUS_MPP,
|
mstatus = set_field(mstatus, MSTATUS_MPP,
|
||||||
riscv_has_ext(env, RVU) ? PRV_U : PRV_M);
|
riscv_has_ext(env, RVU) ? PRV_U : PRV_M);
|
||||||
mstatus = set_field(mstatus, MSTATUS_MPV, 0);
|
mstatus = set_field(mstatus, MSTATUS_MPV, 0);
|
||||||
|
if (riscv_cpu_cfg(env)->ext_ssdbltrp) {
|
||||||
|
mstatus = ssdbltrp_mxret(env, mstatus, prev_priv, prev_virt);
|
||||||
|
}
|
||||||
if ((env->priv_ver >= PRIV_VERSION_1_12_0) && (prev_priv != PRV_M)) {
|
if ((env->priv_ver >= PRIV_VERSION_1_12_0) && (prev_priv != PRV_M)) {
|
||||||
mstatus = set_field(mstatus, MSTATUS_MPRV, 0);
|
mstatus = set_field(mstatus, MSTATUS_MPRV, 0);
|
||||||
}
|
}
|
||||||
@ -402,6 +432,9 @@ target_ulong helper_mnret(CPURISCVState *env)
|
|||||||
if (prev_priv < PRV_M) {
|
if (prev_priv < PRV_M) {
|
||||||
env->mstatus = set_field(env->mstatus, MSTATUS_MPRV, false);
|
env->mstatus = set_field(env->mstatus, MSTATUS_MPRV, false);
|
||||||
}
|
}
|
||||||
|
if (riscv_cpu_cfg(env)->ext_ssdbltrp) {
|
||||||
|
env->mstatus = ssdbltrp_mxret(env, env->mstatus, prev_priv, prev_virt);
|
||||||
|
}
|
||||||
|
|
||||||
if (riscv_has_ext(env, RVH) && prev_virt) {
|
if (riscv_has_ext(env, RVH) && prev_virt) {
|
||||||
riscv_cpu_swap_hypervisor_regs(env);
|
riscv_cpu_swap_hypervisor_regs(env);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user