diff mbox series

[v1,17/28] target/riscv: Add Hypervisor trap return support

Message ID 6e2920dbef1ed86b8784827200525c5a112468b2.1566603412.git.alistair.francis@wdc.com
State New
Headers show
Series Add RISC-V Hypervisor Extension v0.4 | expand

Commit Message

Alistair Francis Aug. 23, 2019, 11:38 p.m. UTC
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/op_helper.c | 66 ++++++++++++++++++++++++++++++++--------
 1 file changed, 54 insertions(+), 12 deletions(-)

Comments

Palmer Dabbelt Oct. 1, 2019, 6:33 p.m. UTC | #1
On Fri, 23 Aug 2019 16:38:34 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/op_helper.c | 66 ++++++++++++++++++++++++++++++++--------
>  1 file changed, 54 insertions(+), 12 deletions(-)
>
> diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
> index beb34e705b..5bcf5d2ff7 100644
> --- a/target/riscv/op_helper.c
> +++ b/target/riscv/op_helper.c
> @@ -73,6 +73,8 @@ target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
>
>  target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
>  {
> +    target_ulong prev_priv, prev_virt, mstatus;
> +
>      if (!(env->priv >= PRV_S)) {
>          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>      }
> @@ -87,16 +89,46 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
>          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>      }
>
> -    target_ulong mstatus = *env->mstatus;
> -    target_ulong prev_priv = get_field(mstatus, MSTATUS_SPP);
> -    mstatus = set_field(mstatus,
> -        env->priv_ver >= PRIV_VERSION_1_10_0 ?
> -        MSTATUS_SIE : MSTATUS_UIE << prev_priv,
> -        get_field(mstatus, MSTATUS_SPIE));
> -    mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
> -    mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
> +    mstatus = *env->mstatus;
> +
> +    if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
> +        /* We support Hypervisor extensions and virtulisation is disabled */
> +        target_ulong hstatus = env->hstatus;
> +
> +        prev_priv = get_field(mstatus, MSTATUS_SPP);
> +        prev_virt = get_field(hstatus, HSTATUS_SPV);
> +
> +        hstatus = set_field(hstatus, HSTATUS_SPV,
> +                                 get_field(hstatus, HSTATUS_SP2V));
> +        mstatus = set_field(mstatus, MSTATUS_SPP,
> +                            get_field(hstatus, HSTATUS_SP2P));
> +        hstatus = set_field(hstatus, HSTATUS_SP2V, 0);
> +        hstatus = set_field(hstatus, HSTATUS_SP2P, 0);
> +        mstatus = set_field(mstatus, SSTATUS_SIE,
> +                            get_field(mstatus, SSTATUS_SPIE));
> +        mstatus = set_field(mstatus, SSTATUS_SPIE, 1);
> +
> +        *env->mstatus = mstatus;
> +        env->hstatus = hstatus;
> +
> +        if (prev_virt == VIRT_ON) {
> +            riscv_cpu_swap_hypervisor_regs(env);
> +        }
> +
> +        riscv_cpu_set_virt_enabled(env, prev_virt);
> +    } else {
> +        prev_priv = get_field(mstatus, MSTATUS_SPP);
> +
> +        mstatus = set_field(mstatus,
> +            env->priv_ver >= PRIV_VERSION_1_10_0 ?
> +            MSTATUS_SIE : MSTATUS_UIE << prev_priv,
> +            get_field(mstatus, MSTATUS_SPIE));
> +        mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
> +        mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
> +        *env->mstatus = mstatus;
> +    }
> +
>      riscv_cpu_set_mode(env, prev_priv);
> -    *env->mstatus = mstatus;
>
>      return retpc;
>  }
> @@ -114,14 +146,24 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
>
>      target_ulong mstatus = *env->mstatus;
>      target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
> +    target_ulong prev_virt = get_field(mstatus, MSTATUS_MPV);
>      mstatus = set_field(mstatus,
>          env->priv_ver >= PRIV_VERSION_1_10_0 ?
>          MSTATUS_MIE : MSTATUS_UIE << prev_priv,
>          get_field(mstatus, MSTATUS_MPIE));
> -    mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
> -    mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
> -    riscv_cpu_set_mode(env, prev_priv);
> +    mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
> +    mstatus = set_field(mstatus, MSTATUS_MPP, 0);
> +    mstatus = set_field(mstatus, MSTATUS_MPV, 0);
>      *env->mstatus = mstatus;
> +    riscv_cpu_set_mode(env, prev_priv);
> +
> +    if (riscv_has_ext(env, RVH)) {
> +        if (prev_virt == VIRT_ON) {
> +            riscv_cpu_swap_hypervisor_regs(env);
> +        }
> +
> +        riscv_cpu_set_virt_enabled(env, prev_virt);
> +    }
>
>      return retpc;
>  }

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>
diff mbox series

Patch

diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index beb34e705b..5bcf5d2ff7 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -73,6 +73,8 @@  target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
 
 target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
 {
+    target_ulong prev_priv, prev_virt, mstatus;
+
     if (!(env->priv >= PRV_S)) {
         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
     }
@@ -87,16 +89,46 @@  target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
     }
 
-    target_ulong mstatus = *env->mstatus;
-    target_ulong prev_priv = get_field(mstatus, MSTATUS_SPP);
-    mstatus = set_field(mstatus,
-        env->priv_ver >= PRIV_VERSION_1_10_0 ?
-        MSTATUS_SIE : MSTATUS_UIE << prev_priv,
-        get_field(mstatus, MSTATUS_SPIE));
-    mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
-    mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
+    mstatus = *env->mstatus;
+
+    if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
+        /* We support Hypervisor extensions and virtulisation is disabled */
+        target_ulong hstatus = env->hstatus;
+
+        prev_priv = get_field(mstatus, MSTATUS_SPP);
+        prev_virt = get_field(hstatus, HSTATUS_SPV);
+
+        hstatus = set_field(hstatus, HSTATUS_SPV,
+                                 get_field(hstatus, HSTATUS_SP2V));
+        mstatus = set_field(mstatus, MSTATUS_SPP,
+                            get_field(hstatus, HSTATUS_SP2P));
+        hstatus = set_field(hstatus, HSTATUS_SP2V, 0);
+        hstatus = set_field(hstatus, HSTATUS_SP2P, 0);
+        mstatus = set_field(mstatus, SSTATUS_SIE,
+                            get_field(mstatus, SSTATUS_SPIE));
+        mstatus = set_field(mstatus, SSTATUS_SPIE, 1);
+
+        *env->mstatus = mstatus;
+        env->hstatus = hstatus;
+
+        if (prev_virt == VIRT_ON) {
+            riscv_cpu_swap_hypervisor_regs(env);
+        }
+
+        riscv_cpu_set_virt_enabled(env, prev_virt);
+    } else {
+        prev_priv = get_field(mstatus, MSTATUS_SPP);
+
+        mstatus = set_field(mstatus,
+            env->priv_ver >= PRIV_VERSION_1_10_0 ?
+            MSTATUS_SIE : MSTATUS_UIE << prev_priv,
+            get_field(mstatus, MSTATUS_SPIE));
+        mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
+        mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
+        *env->mstatus = mstatus;
+    }
+
     riscv_cpu_set_mode(env, prev_priv);
-    *env->mstatus = mstatus;
 
     return retpc;
 }
@@ -114,14 +146,24 @@  target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
 
     target_ulong mstatus = *env->mstatus;
     target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
+    target_ulong prev_virt = get_field(mstatus, MSTATUS_MPV);
     mstatus = set_field(mstatus,
         env->priv_ver >= PRIV_VERSION_1_10_0 ?
         MSTATUS_MIE : MSTATUS_UIE << prev_priv,
         get_field(mstatus, MSTATUS_MPIE));
-    mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
-    mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
-    riscv_cpu_set_mode(env, prev_priv);
+    mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
+    mstatus = set_field(mstatus, MSTATUS_MPP, 0);
+    mstatus = set_field(mstatus, MSTATUS_MPV, 0);
     *env->mstatus = mstatus;
+    riscv_cpu_set_mode(env, prev_priv);
+
+    if (riscv_has_ext(env, RVH)) {
+        if (prev_virt == VIRT_ON) {
+            riscv_cpu_swap_hypervisor_regs(env);
+        }
+
+        riscv_cpu_set_virt_enabled(env, prev_virt);
+    }
 
     return retpc;
 }