Message ID | 7ee4badbb4dfc33ab2e75151b69559f09d733575.1580518859.git.alistair.francis@wdc.com |
---|---|
State | New |
Headers | show |
Series | Add RISC-V Hypervisor Extension v0.5 | expand |
On Fri, 31 Jan 2020 17:02:30 PST (-0800), Alistair Francis wrote: > Signed-off-by: Alistair Francis <alistair.francis@wdc.com> > --- > target/riscv/cpu_helper.c | 69 +++++++++++++++++++++++++++++++++------ > 1 file changed, 59 insertions(+), 10 deletions(-) > > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c > index 98017df33b..e7728cb0ca 100644 > --- a/target/riscv/cpu_helper.c > +++ b/target/riscv/cpu_helper.c > @@ -639,6 +639,8 @@ void riscv_cpu_do_interrupt(CPUState *cs) > > RISCVCPU *cpu = RISCV_CPU(cs); > CPURISCVState *env = &cpu->env; > + bool force_hs_execp = riscv_cpu_force_hs_excep_enabled(env); > + target_ulong s; > > /* cs->exception is 32-bits wide unlike mcause which is XLEN-bits wide > * so we mask off the MSB and separate into trap type and cause. > @@ -648,19 +650,14 @@ void riscv_cpu_do_interrupt(CPUState *cs) > target_ulong deleg = async ? env->mideleg : env->medeleg; > target_ulong tval = 0; > > - static const int ecall_cause_map[] = { > - [PRV_U] = RISCV_EXCP_U_ECALL, > - [PRV_S] = RISCV_EXCP_S_ECALL, > - [PRV_H] = RISCV_EXCP_VS_ECALL, > - [PRV_M] = RISCV_EXCP_M_ECALL > - }; > - > if (!async) { > /* set tval to badaddr for traps with address information */ > switch (cause) { > case RISCV_EXCP_INST_GUEST_PAGE_FAULT: > case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT: > case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT: > + force_hs_execp = true; > + /* fallthrough */ > case RISCV_EXCP_INST_ADDR_MIS: > case RISCV_EXCP_INST_ACCESS_FAULT: > case RISCV_EXCP_LOAD_ADDR_MIS: > @@ -678,7 +675,16 @@ void riscv_cpu_do_interrupt(CPUState *cs) > /* ecall is dispatched as one cause so translate based on mode */ > if (cause == RISCV_EXCP_U_ECALL) { > assert(env->priv <= 3); > - cause = ecall_cause_map[env->priv]; > + > + if (env->priv == PRV_M) { > + cause = RISCV_EXCP_M_ECALL; > + } else if (env->priv == PRV_S && riscv_cpu_virt_enabled(env)) { > + cause = RISCV_EXCP_VS_ECALL; > + } else if (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) { > + cause = RISCV_EXCP_S_ECALL; > + } else if (env->priv == PRV_U) { > + cause = RISCV_EXCP_U_ECALL; > + } > } > } > > @@ -688,7 +694,36 @@ void riscv_cpu_do_interrupt(CPUState *cs) > if (env->priv <= PRV_S && > cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) { > /* handle the trap in S-mode */ > - target_ulong s = env->mstatus; > + if (riscv_has_ext(env, RVH)) { > + target_ulong hdeleg = async ? env->hideleg : env->hedeleg; > + > + if (riscv_cpu_virt_enabled(env) && ((hdeleg >> cause) & 1) && > + !force_hs_execp) { > + /* Trap to VS mode */ > + } else if (riscv_cpu_virt_enabled(env)) { > + /* Trap into HS mode, from virt */ > + riscv_cpu_swap_hypervisor_regs(env); > + env->hstatus = set_field(env->hstatus, HSTATUS_SP2V, > + get_field(env->hstatus, HSTATUS_SPV)); > + env->hstatus = set_field(env->hstatus, HSTATUS_SP2P, > + get_field(env->mstatus, SSTATUS_SPP)); > + env->hstatus = set_field(env->hstatus, HSTATUS_SPV, > + riscv_cpu_virt_enabled(env)); > + > + riscv_cpu_set_virt_enabled(env, 0); > + riscv_cpu_set_force_hs_excep(env, 0); > + } else { > + /* Trap into HS mode */ > + env->hstatus = set_field(env->hstatus, HSTATUS_SP2V, > + get_field(env->hstatus, HSTATUS_SPV)); > + env->hstatus = set_field(env->hstatus, HSTATUS_SP2P, > + get_field(env->mstatus, SSTATUS_SPP)); > + env->hstatus = set_field(env->hstatus, HSTATUS_SPV, > + riscv_cpu_virt_enabled(env)); > + } > + } > + > + s = env->mstatus; > s = set_field(s, MSTATUS_SPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ? > get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE << env->priv)); > s = set_field(s, MSTATUS_SPP, env->priv); > @@ -702,7 +737,21 @@ void riscv_cpu_do_interrupt(CPUState *cs) > riscv_cpu_set_mode(env, PRV_S); > } else { > /* handle the trap in M-mode */ > - target_ulong s = env->mstatus; > + if (riscv_has_ext(env, RVH)) { > + if (riscv_cpu_virt_enabled(env)) { > + riscv_cpu_swap_hypervisor_regs(env); > + } > + env->mstatus = set_field(env->mstatus, MSTATUS_MPV, > + riscv_cpu_virt_enabled(env)); > + env->mstatus = set_field(env->mstatus, MSTATUS_MTL, > + riscv_cpu_force_hs_excep_enabled(env)); > + > + /* Trapping to M mode, virt is disabled */ > + riscv_cpu_set_virt_enabled(env, 0); > + riscv_cpu_set_force_hs_excep(env, 0); > + } > + > + s = env->mstatus; > s = set_field(s, MSTATUS_MPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ? > get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE << env->priv)); > s = set_field(s, MSTATUS_MPP, env->priv); Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com>
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 98017df33b..e7728cb0ca 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -639,6 +639,8 @@ void riscv_cpu_do_interrupt(CPUState *cs) RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; + bool force_hs_execp = riscv_cpu_force_hs_excep_enabled(env); + target_ulong s; /* cs->exception is 32-bits wide unlike mcause which is XLEN-bits wide * so we mask off the MSB and separate into trap type and cause. @@ -648,19 +650,14 @@ void riscv_cpu_do_interrupt(CPUState *cs) target_ulong deleg = async ? env->mideleg : env->medeleg; target_ulong tval = 0; - static const int ecall_cause_map[] = { - [PRV_U] = RISCV_EXCP_U_ECALL, - [PRV_S] = RISCV_EXCP_S_ECALL, - [PRV_H] = RISCV_EXCP_VS_ECALL, - [PRV_M] = RISCV_EXCP_M_ECALL - }; - if (!async) { /* set tval to badaddr for traps with address information */ switch (cause) { case RISCV_EXCP_INST_GUEST_PAGE_FAULT: case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT: case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT: + force_hs_execp = true; + /* fallthrough */ case RISCV_EXCP_INST_ADDR_MIS: case RISCV_EXCP_INST_ACCESS_FAULT: case RISCV_EXCP_LOAD_ADDR_MIS: @@ -678,7 +675,16 @@ void riscv_cpu_do_interrupt(CPUState *cs) /* ecall is dispatched as one cause so translate based on mode */ if (cause == RISCV_EXCP_U_ECALL) { assert(env->priv <= 3); - cause = ecall_cause_map[env->priv]; + + if (env->priv == PRV_M) { + cause = RISCV_EXCP_M_ECALL; + } else if (env->priv == PRV_S && riscv_cpu_virt_enabled(env)) { + cause = RISCV_EXCP_VS_ECALL; + } else if (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) { + cause = RISCV_EXCP_S_ECALL; + } else if (env->priv == PRV_U) { + cause = RISCV_EXCP_U_ECALL; + } } } @@ -688,7 +694,36 @@ void riscv_cpu_do_interrupt(CPUState *cs) if (env->priv <= PRV_S && cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) { /* handle the trap in S-mode */ - target_ulong s = env->mstatus; + if (riscv_has_ext(env, RVH)) { + target_ulong hdeleg = async ? env->hideleg : env->hedeleg; + + if (riscv_cpu_virt_enabled(env) && ((hdeleg >> cause) & 1) && + !force_hs_execp) { + /* Trap to VS mode */ + } else if (riscv_cpu_virt_enabled(env)) { + /* Trap into HS mode, from virt */ + riscv_cpu_swap_hypervisor_regs(env); + env->hstatus = set_field(env->hstatus, HSTATUS_SP2V, + get_field(env->hstatus, HSTATUS_SPV)); + env->hstatus = set_field(env->hstatus, HSTATUS_SP2P, + get_field(env->mstatus, SSTATUS_SPP)); + env->hstatus = set_field(env->hstatus, HSTATUS_SPV, + riscv_cpu_virt_enabled(env)); + + riscv_cpu_set_virt_enabled(env, 0); + riscv_cpu_set_force_hs_excep(env, 0); + } else { + /* Trap into HS mode */ + env->hstatus = set_field(env->hstatus, HSTATUS_SP2V, + get_field(env->hstatus, HSTATUS_SPV)); + env->hstatus = set_field(env->hstatus, HSTATUS_SP2P, + get_field(env->mstatus, SSTATUS_SPP)); + env->hstatus = set_field(env->hstatus, HSTATUS_SPV, + riscv_cpu_virt_enabled(env)); + } + } + + s = env->mstatus; s = set_field(s, MSTATUS_SPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ? get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE << env->priv)); s = set_field(s, MSTATUS_SPP, env->priv); @@ -702,7 +737,21 @@ void riscv_cpu_do_interrupt(CPUState *cs) riscv_cpu_set_mode(env, PRV_S); } else { /* handle the trap in M-mode */ - target_ulong s = env->mstatus; + if (riscv_has_ext(env, RVH)) { + if (riscv_cpu_virt_enabled(env)) { + riscv_cpu_swap_hypervisor_regs(env); + } + env->mstatus = set_field(env->mstatus, MSTATUS_MPV, + riscv_cpu_virt_enabled(env)); + env->mstatus = set_field(env->mstatus, MSTATUS_MTL, + riscv_cpu_force_hs_excep_enabled(env)); + + /* Trapping to M mode, virt is disabled */ + riscv_cpu_set_virt_enabled(env, 0); + riscv_cpu_set_force_hs_excep(env, 0); + } + + s = env->mstatus; s = set_field(s, MSTATUS_MPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ? get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE << env->priv)); s = set_field(s, MSTATUS_MPP, env->priv);
Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_helper.c | 69 +++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 10 deletions(-)