diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/riscv/cpu.h | 3 | ||||
-rw-r--r-- | target/riscv/cpu_bits.h | 1 | ||||
-rw-r--r-- | target/riscv/cpu_helper.c | 60 | ||||
-rw-r--r-- | target/riscv/op_helper.c | 12 |
4 files changed, 25 insertions, 51 deletions
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 5d8e54c426..0cf48a1521 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -323,8 +323,7 @@ bool riscv_cpu_virt_enabled(CPURISCVState *env); void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable); bool riscv_cpu_force_hs_excep_enabled(CPURISCVState *env); void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable); -bool riscv_cpu_two_stage_lookup(CPURISCVState *env); -void riscv_cpu_set_two_stage_lookup(CPURISCVState *env, bool enable); +bool riscv_cpu_two_stage_lookup(int mmu_idx); int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch); hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index daedad8691..24b24c69c5 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -469,7 +469,6 @@ * page table fault. */ #define FORCE_HS_EXCEP 2 -#define HS_TWO_STAGE 4 /* RV32 satp CSR field masks */ #define SATP32_MODE 0x80000000 diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 9dfa7af401..a2787b1d48 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -207,22 +207,9 @@ void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable) env->virt = set_field(env->virt, FORCE_HS_EXCEP, enable); } -bool riscv_cpu_two_stage_lookup(CPURISCVState *env) +bool riscv_cpu_two_stage_lookup(int mmu_idx) { - if (!riscv_has_ext(env, RVH)) { - return false; - } - - return get_field(env->virt, HS_TWO_STAGE); -} - -void riscv_cpu_set_two_stage_lookup(CPURISCVState *env, bool enable) -{ - if (!riscv_has_ext(env, RVH)) { - return; - } - - env->virt = set_field(env->virt, HS_TWO_STAGE, enable); + return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK; } int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) @@ -333,7 +320,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, * was called. Background registers will be used if the guest has * forced a two stage translation to be on (in HS or M mode). */ - if (riscv_cpu_two_stage_lookup(env) && access_type != MMU_INST_FETCH) { + if (!riscv_cpu_virt_enabled(env) && riscv_cpu_two_stage_lookup(mmu_idx)) { use_background = true; } @@ -572,7 +559,7 @@ restart: static void raise_mmu_exception(CPURISCVState *env, target_ulong address, MMUAccessType access_type, bool pmp_violation, - bool first_stage) + bool first_stage, bool two_stage) { CPUState *cs = env_cpu(env); int page_fault_exceptions; @@ -595,8 +582,7 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address, } break; case MMU_DATA_LOAD: - if ((riscv_cpu_virt_enabled(env) || riscv_cpu_two_stage_lookup(env)) && - !first_stage) { + if (two_stage && !first_stage) { cs->exception_index = RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT; } else { cs->exception_index = page_fault_exceptions ? @@ -604,8 +590,7 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address, } break; case MMU_DATA_STORE: - if ((riscv_cpu_virt_enabled(env) || riscv_cpu_two_stage_lookup(env)) && - !first_stage) { + if (two_stage && !first_stage) { cs->exception_index = RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT; } else { cs->exception_index = page_fault_exceptions ? @@ -696,6 +681,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, int prot, prot2; bool pmp_violation = false; bool first_stage_error = true; + bool two_stage_lookup = false; int ret = TRANSLATE_FAIL; int mode = mmu_idx; target_ulong tlb_size = 0; @@ -715,11 +701,12 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, access_type != MMU_INST_FETCH && get_field(env->mstatus, MSTATUS_MPRV) && get_field(env->mstatus, MSTATUS_MPV)) { - riscv_cpu_set_two_stage_lookup(env, true); + two_stage_lookup = true; } if (riscv_cpu_virt_enabled(env) || - (riscv_cpu_two_stage_lookup(env) && access_type != MMU_INST_FETCH)) { + ((riscv_cpu_two_stage_lookup(mmu_idx) || two_stage_lookup) && + access_type != MMU_INST_FETCH)) { /* Two stage lookup */ ret = get_physical_address(env, &pa, &prot, address, &env->guest_phys_fault_addr, access_type, @@ -782,14 +769,6 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, __func__, address, ret, pa, prot); } - /* We did the two stage lookup based on MPRV, unset the lookup */ - if (riscv_has_ext(env, RVH) && env->priv == PRV_M && - access_type != MMU_INST_FETCH && - get_field(env->mstatus, MSTATUS_MPRV) && - get_field(env->mstatus, MSTATUS_MPV)) { - riscv_cpu_set_two_stage_lookup(env, false); - } - if (riscv_feature(env, RISCV_FEATURE_PMP) && (ret == TRANSLATE_SUCCESS) && !pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) { @@ -811,7 +790,10 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } else if (probe) { return false; } else { - raise_mmu_exception(env, address, access_type, pmp_violation, first_stage_error); + raise_mmu_exception(env, address, access_type, pmp_violation, + first_stage_error, + riscv_cpu_virt_enabled(env) || + riscv_cpu_two_stage_lookup(mmu_idx)); riscv_raise_exception(env, cs->exception_index, retaddr); } @@ -915,9 +897,16 @@ void riscv_cpu_do_interrupt(CPUState *cs) /* handle the trap in S-mode */ if (riscv_has_ext(env, RVH)) { target_ulong hdeleg = async ? env->hideleg : env->hedeleg; + bool two_stage_lookup = false; + + if (env->priv == PRV_M || + (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) || + (env->priv == PRV_U && !riscv_cpu_virt_enabled(env) && + get_field(env->hstatus, HSTATUS_HU))) { + two_stage_lookup = true; + } - if ((riscv_cpu_virt_enabled(env) || - riscv_cpu_two_stage_lookup(env)) && write_tval) { + if ((riscv_cpu_virt_enabled(env) || two_stage_lookup) && write_tval) { /* * If we are writing a guest virtual address to stval, set * this to 1. If we are trapping to VS we will set this to 0 @@ -955,11 +944,10 @@ void riscv_cpu_do_interrupt(CPUState *cs) riscv_cpu_set_force_hs_excep(env, 0); } else { /* Trap into HS mode */ - if (!riscv_cpu_two_stage_lookup(env)) { + if (!two_stage_lookup) { env->hstatus = set_field(env->hstatus, HSTATUS_SPV, riscv_cpu_virt_enabled(env)); } - riscv_cpu_set_two_stage_lookup(env, false); htval = env->guest_phys_fault_addr; } } diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 548c5851ec..5759850e69 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -237,8 +237,6 @@ target_ulong helper_hyp_load(CPURISCVState *env, target_ulong address, target_ulong pte; int mmu_idx = cpu_mmu_index(env, false) | TB_FLAGS_PRIV_HYP_ACCESS_MASK; - riscv_cpu_set_two_stage_lookup(env, true); - switch (memop) { case MO_SB: pte = cpu_ldsb_mmuidx_ra(env, address, mmu_idx, GETPC()); @@ -265,8 +263,6 @@ target_ulong helper_hyp_load(CPURISCVState *env, target_ulong address, g_assert_not_reached(); } - riscv_cpu_set_two_stage_lookup(env, false); - return pte; } @@ -287,8 +283,6 @@ void helper_hyp_store(CPURISCVState *env, target_ulong address, get_field(env->hstatus, HSTATUS_HU))) { int mmu_idx = cpu_mmu_index(env, false) | TB_FLAGS_PRIV_HYP_ACCESS_MASK; - riscv_cpu_set_two_stage_lookup(env, true); - switch (memop) { case MO_SB: case MO_UB: @@ -309,8 +303,6 @@ void helper_hyp_store(CPURISCVState *env, target_ulong address, g_assert_not_reached(); } - riscv_cpu_set_two_stage_lookup(env, false); - return; } @@ -331,8 +323,6 @@ target_ulong helper_hyp_x_load(CPURISCVState *env, target_ulong address, target_ulong pte; int mmu_idx = cpu_mmu_index(env, false) | TB_FLAGS_PRIV_HYP_ACCESS_MASK; - riscv_cpu_set_two_stage_lookup(env, true); - switch (memop) { case MO_TEUW: pte = cpu_lduw_mmuidx_ra(env, address, mmu_idx, GETPC()); @@ -344,8 +334,6 @@ target_ulong helper_hyp_x_load(CPURISCVState *env, target_ulong address, g_assert_not_reached(); } - riscv_cpu_set_two_stage_lookup(env, false); - return pte; } |