Transform the fetch address before page walk when pointer mask is enabled for instruction fetch.
Signed-off-by: Weiwei Li <liwei...@iscas.ac.cn> Signed-off-by: Junqiang Wang <wangjunqi...@iscas.ac.cn> --- target/riscv/cpu.h | 1 + target/riscv/cpu_helper.c | 25 +++++++++++++++++++++++-- target/riscv/csr.c | 2 -- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 638e47c75a..57bd9c3279 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -368,6 +368,7 @@ struct CPUArchState { #endif target_ulong cur_pmmask; target_ulong cur_pmbase; + bool cur_pminsn; /* Fields from here on are preserved across CPU reset. */ QEMUTimer *stimer; /* Internal timer for S-mode interrupt */ diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index f88c503cf4..77132a3e0c 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -124,6 +124,7 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, void riscv_cpu_update_mask(CPURISCVState *env) { target_ulong mask = -1, base = 0; + bool insn = false; /* * TODO: Current RVJ spec does not specify * how the extension interacts with XLEN. @@ -135,18 +136,21 @@ void riscv_cpu_update_mask(CPURISCVState *env) if (env->mmte & M_PM_ENABLE) { mask = env->mpmmask; base = env->mpmbase; + insn = env->mmte & MMTE_M_PM_INSN; } break; case PRV_S: if (env->mmte & S_PM_ENABLE) { mask = env->spmmask; base = env->spmbase; + insn = env->mmte & MMTE_S_PM_INSN; } break; case PRV_U: if (env->mmte & U_PM_ENABLE) { mask = env->upmmask; base = env->upmbase; + insn = env->mmte & MMTE_U_PM_INSN; } break; default: @@ -161,6 +165,7 @@ void riscv_cpu_update_mask(CPURISCVState *env) env->cur_pmmask = mask; env->cur_pmbase = base; } + env->cur_pminsn = insn; } #ifndef CONFIG_USER_ONLY @@ -1225,6 +1230,17 @@ static void pmu_tlb_fill_incr_ctr(RISCVCPU *cpu, MMUAccessType access_type) riscv_pmu_incr_ctr(cpu, pmu_event_type); } +static target_ulong adjust_pc_address(CPURISCVState *env, target_ulong pc) +{ + target_ulong adjust_pc = pc; + + if (env->cur_pminsn) { + adjust_pc = (adjust_pc & ~env->cur_pmmask) | env->cur_pmbase; + } + + return adjust_pc; +} + bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr) @@ -1232,6 +1248,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; vaddr im_address; + vaddr orig_address = address; hwaddr pa = 0; int prot, prot2, prot_pmp; bool pmp_violation = false; @@ -1248,6 +1265,10 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n", __func__, address, access_type, mmu_idx); + if (access_type == MMU_INST_FETCH) { + address = adjust_pc_address(env, address); + } + /* MPRV does not affect the virtual-machine load/store instructions, HLV, HLVX, and HSV. */ if (riscv_cpu_two_stage_lookup(mmu_idx)) { @@ -1351,13 +1372,13 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } if (ret == TRANSLATE_SUCCESS) { - tlb_set_page(cs, address & ~(tlb_size - 1), pa & ~(tlb_size - 1), + tlb_set_page(cs, orig_address & ~(tlb_size - 1), pa & ~(tlb_size - 1), prot, mmu_idx, tlb_size); return true; } else if (probe) { return false; } else { - raise_mmu_exception(env, address, access_type, pmp_violation, + raise_mmu_exception(env, orig_address, access_type, pmp_violation, first_stage_error, riscv_cpu_virt_enabled(env) || riscv_cpu_two_stage_lookup(mmu_idx), diff --git a/target/riscv/csr.c b/target/riscv/csr.c index d522efc0b6..4544c9d934 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -3511,8 +3511,6 @@ static RISCVException write_mmte(CPURISCVState *env, int csrno, /* for machine mode pm.current is hardwired to 1 */ wpri_val |= MMTE_M_PM_CURRENT; - /* hardwiring pm.instruction bit to 0, since it's not supported yet */ - wpri_val &= ~(MMTE_M_PM_INSN | MMTE_S_PM_INSN | MMTE_U_PM_INSN); env->mmte = wpri_val | PM_EXT_DIRTY; riscv_cpu_update_mask(env); -- 2.25.1