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>