Skip to content

Commit 72d71d8

Browse files
clementlegeralistair23
authored andcommitted
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 <[email protected]> Reviewed-by: Alistair Francis <[email protected]> Message-ID: <[email protected]> Signed-off-by: Alistair Francis <[email protected]>
1 parent 0aadf81 commit 72d71d8

File tree

1 file changed

+34
-1
lines changed

1 file changed

+34
-1
lines changed

target/riscv/op_helper.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,18 @@ target_ulong helper_sret(CPURISCVState *env)
294294
get_field(mstatus, MSTATUS_SPIE));
295295
mstatus = set_field(mstatus, MSTATUS_SPIE, 1);
296296
mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
297+
298+
if (riscv_cpu_cfg(env)->ext_ssdbltrp) {
299+
if (riscv_has_ext(env, RVH)) {
300+
target_ulong prev_vu = get_field(env->hstatus, HSTATUS_SPV) &&
301+
prev_priv == PRV_U;
302+
/* Returning to VU from HS, vsstatus.sdt = 0 */
303+
if (!env->virt_enabled && prev_vu) {
304+
env->vsstatus = set_field(env->vsstatus, MSTATUS_SDT, 0);
305+
}
306+
}
307+
mstatus = set_field(mstatus, MSTATUS_SDT, 0);
308+
}
297309
if (env->priv_ver >= PRIV_VERSION_1_12_0) {
298310
mstatus = set_field(mstatus, MSTATUS_MPRV, 0);
299311
}
@@ -304,7 +316,6 @@ target_ulong helper_sret(CPURISCVState *env)
304316
target_ulong hstatus = env->hstatus;
305317

306318
prev_virt = get_field(hstatus, HSTATUS_SPV);
307-
308319
hstatus = set_field(hstatus, HSTATUS_SPV, 0);
309320

310321
env->hstatus = hstatus;
@@ -344,6 +355,22 @@ static void check_ret_from_m_mode(CPURISCVState *env, target_ulong retpc,
344355
riscv_raise_exception(env, RISCV_EXCP_INST_ACCESS_FAULT, GETPC());
345356
}
346357
}
358+
static target_ulong ssdbltrp_mxret(CPURISCVState *env, target_ulong mstatus,
359+
target_ulong prev_priv,
360+
target_ulong prev_virt)
361+
{
362+
/* If returning to U, VS or VU, sstatus.sdt = 0 */
363+
if (prev_priv == PRV_U || (prev_virt &&
364+
(prev_priv == PRV_S || prev_priv == PRV_U))) {
365+
mstatus = set_field(mstatus, MSTATUS_SDT, 0);
366+
/* If returning to VU, vsstatus.sdt = 0 */
367+
if (prev_virt && prev_priv == PRV_U) {
368+
env->vsstatus = set_field(env->vsstatus, MSTATUS_SDT, 0);
369+
}
370+
}
371+
372+
return mstatus;
373+
}
347374

348375
target_ulong helper_mret(CPURISCVState *env)
349376
{
@@ -361,6 +388,9 @@ target_ulong helper_mret(CPURISCVState *env)
361388
mstatus = set_field(mstatus, MSTATUS_MPP,
362389
riscv_has_ext(env, RVU) ? PRV_U : PRV_M);
363390
mstatus = set_field(mstatus, MSTATUS_MPV, 0);
391+
if (riscv_cpu_cfg(env)->ext_ssdbltrp) {
392+
mstatus = ssdbltrp_mxret(env, mstatus, prev_priv, prev_virt);
393+
}
364394
if ((env->priv_ver >= PRIV_VERSION_1_12_0) && (prev_priv != PRV_M)) {
365395
mstatus = set_field(mstatus, MSTATUS_MPRV, 0);
366396
}
@@ -402,6 +432,9 @@ target_ulong helper_mnret(CPURISCVState *env)
402432
if (prev_priv < PRV_M) {
403433
env->mstatus = set_field(env->mstatus, MSTATUS_MPRV, false);
404434
}
435+
if (riscv_cpu_cfg(env)->ext_ssdbltrp) {
436+
env->mstatus = ssdbltrp_mxret(env, env->mstatus, prev_priv, prev_virt);
437+
}
405438

406439
if (riscv_has_ext(env, RVH) && prev_virt) {
407440
riscv_cpu_swap_hypervisor_regs(env);

0 commit comments

Comments
 (0)