diff options
Diffstat (limited to 'target/riscv/cpu_helper.c')
| -rw-r--r-- | target/riscv/cpu_helper.c | 99 |
1 files changed, 51 insertions, 48 deletions
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 434a83e66a..327a2c4f1d 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -35,46 +35,18 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) #endif } -static RISCVMXL cpu_get_xl(CPURISCVState *env) -{ -#if defined(TARGET_RISCV32) - return MXL_RV32; -#elif defined(CONFIG_USER_ONLY) - return MXL_RV64; -#else - RISCVMXL xl = riscv_cpu_mxl(env); - - /* - * When emulating a 32-bit-only cpu, use RV32. - * When emulating a 64-bit cpu, and MXL has been reduced to RV32, - * MSTATUSH doesn't have UXL/SXL, therefore XLEN cannot be widened - * back to RV64 for lower privs. - */ - if (xl != MXL_RV32) { - switch (env->priv) { - case PRV_M: - break; - case PRV_U: - xl = get_field(env->mstatus, MSTATUS64_UXL); - break; - default: /* PRV_S | PRV_H */ - xl = get_field(env->mstatus, MSTATUS64_SXL); - break; - } - } - return xl; -#endif -} - void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *pflags) { + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + uint32_t flags = 0; - *pc = env->pc; + *pc = env->xl == MXL_RV32 ? env->pc & UINT32_MAX : env->pc; *cs_base = 0; - if (riscv_has_ext(env, RVV)) { + if (riscv_has_ext(env, RVV) || cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) { /* * If env->vl equals to VLMAX, we can use generic vector operation * expanders (GVEC) to accerlate the vector operations. @@ -88,8 +60,7 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, uint32_t maxsz = vlmax << sew; bool vl_eq_vlmax = (env->vstart == 0) && (vlmax == env->vl) && (maxsz >= 8); - flags = FIELD_DP32(flags, TB_FLAGS, VILL, - FIELD_EX64(env->vtype, VTYPE, VILL)); + flags = FIELD_DP32(flags, TB_FLAGS, VILL, env->vill); flags = FIELD_DP32(flags, TB_FLAGS, SEW, sew); flags = FIELD_DP32(flags, TB_FLAGS, LMUL, FIELD_EX64(env->vtype, VTYPE, VLMUL)); @@ -125,29 +96,59 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, flags = FIELD_DP32(flags, TB_FLAGS, MSTATUS_HS_VS, get_field(env->mstatus_hs, MSTATUS_VS)); } +#endif + + flags = FIELD_DP32(flags, TB_FLAGS, XL, env->xl); + if (env->cur_pmmask < (env->xl == MXL_RV32 ? UINT32_MAX : UINT64_MAX)) { + flags = FIELD_DP32(flags, TB_FLAGS, PM_MASK_ENABLED, 1); + } + if (env->cur_pmbase != 0) { + flags = FIELD_DP32(flags, TB_FLAGS, PM_BASE_ENABLED, 1); + } + + *pflags = flags; +} + +void riscv_cpu_update_mask(CPURISCVState *env) +{ + target_ulong mask = -1, base = 0; + /* + * TODO: Current RVJ spec does not specify + * how the extension interacts with XLEN. + */ +#ifndef CONFIG_USER_ONLY if (riscv_has_ext(env, RVJ)) { - int priv = flags & TB_FLAGS_PRIV_MMU_MASK; - bool pm_enabled = false; - switch (priv) { - case PRV_U: - pm_enabled = env->mmte & U_PM_ENABLE; + switch (env->priv) { + case PRV_M: + if (env->mmte & M_PM_ENABLE) { + mask = env->mpmmask; + base = env->mpmbase; + } break; case PRV_S: - pm_enabled = env->mmte & S_PM_ENABLE; + if (env->mmte & S_PM_ENABLE) { + mask = env->spmmask; + base = env->spmbase; + } break; - case PRV_M: - pm_enabled = env->mmte & M_PM_ENABLE; + case PRV_U: + if (env->mmte & U_PM_ENABLE) { + mask = env->upmmask; + base = env->upmbase; + } break; default: g_assert_not_reached(); } - flags = FIELD_DP32(flags, TB_FLAGS, PM_ENABLED, pm_enabled); } #endif - - flags = FIELD_DP32(flags, TB_FLAGS, XL, cpu_get_xl(env)); - - *pflags = flags; + if (env->xl == MXL_RV32) { + env->cur_pmmask = mask & UINT32_MAX; + env->cur_pmbase = base & UINT32_MAX; + } else { + env->cur_pmmask = mask; + env->cur_pmbase = base; + } } #ifndef CONFIG_USER_ONLY @@ -361,6 +362,8 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) } /* tlb_flush is unnecessary as mode is contained in mmu_idx */ env->priv = newpriv; + env->xl = cpu_recompute_xl(env); + riscv_cpu_update_mask(env); /* * Clear the load reservation - otherwise a reservation placed in one |