Message ID | 6e2920dbef1ed86b8784827200525c5a112468b2.1566603412.git.alistair.francis@wdc.com |
---|---|
State | New |
Headers | show |
Series | Add RISC-V Hypervisor Extension v0.4 | expand |
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 --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; }
Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/op_helper.c | 66 ++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 12 deletions(-)