aboutsummaryrefslogtreecommitdiff
path: root/target/riscv/cpu_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/riscv/cpu_helper.c')
-rw-r--r--target/riscv/cpu_helper.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index e36ee7d58e..9d5a06499f 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -82,6 +82,67 @@ bool riscv_cpu_fp_enabled(CPURISCVState *env)
return false;
}
+void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env)
+{
+ target_ulong mstatus_mask = MSTATUS_MXR | MSTATUS_SUM | MSTATUS_FS |
+ MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE;
+ bool current_virt = riscv_cpu_virt_enabled(env);
+
+ g_assert(riscv_has_ext(env, RVH));
+
+#if defined(TARGET_RISCV64)
+ mstatus_mask |= MSTATUS64_UXL;
+#endif
+
+ if (current_virt) {
+ /* Current V=1 and we are about to change to V=0 */
+ env->vsstatus = env->mstatus & mstatus_mask;
+ env->mstatus &= ~mstatus_mask;
+ env->mstatus |= env->mstatus_hs;
+
+ env->vstvec = env->stvec;
+ env->stvec = env->stvec_hs;
+
+ env->vsscratch = env->sscratch;
+ env->sscratch = env->sscratch_hs;
+
+ env->vsepc = env->sepc;
+ env->sepc = env->sepc_hs;
+
+ env->vscause = env->scause;
+ env->scause = env->scause_hs;
+
+ env->vstval = env->sbadaddr;
+ env->sbadaddr = env->stval_hs;
+
+ env->vsatp = env->satp;
+ env->satp = env->satp_hs;
+ } else {
+ /* Current V=0 and we are about to change to V=1 */
+ env->mstatus_hs = env->mstatus & mstatus_mask;
+ env->mstatus &= ~mstatus_mask;
+ env->mstatus |= env->vsstatus;
+
+ env->stvec_hs = env->stvec;
+ env->stvec = env->vstvec;
+
+ env->sscratch_hs = env->sscratch;
+ env->sscratch = env->vsscratch;
+
+ env->sepc_hs = env->sepc;
+ env->sepc = env->vsepc;
+
+ env->scause_hs = env->scause;
+ env->scause = env->vscause;
+
+ env->stval_hs = env->sbadaddr;
+ env->sbadaddr = env->vstval;
+
+ env->satp_hs = env->satp;
+ env->satp = env->vsatp;
+ }
+}
+
bool riscv_cpu_virt_enabled(CPURISCVState *env)
{
if (!riscv_has_ext(env, RVH)) {