diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 0c58c8571f..a2881bfa38 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -884,6 +884,17 @@ static void riscv_cpu_reset_hold(Object *obj) } /* mmte is supposed to have pm.current hardwired to 1 */ env->mmte |= (EXT_STATUS_INITIAL | MMTE_M_PM_CURRENT); + + /* + * Clear mseccfg and unlock all the PMP entries upon reset. + * This is allowed as per the priv and smepmp specifications + * and is needed to clear stale entries across reboots. + */ + if (riscv_cpu_cfg(env)->ext_smepmp) { + env->mseccfg = 0; + } + + pmp_unlock_entries(env); #endif env->xl = riscv_cpu_mxl(env); riscv_cpu_update_mask(env); diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 21d2489e27..4dfaa28fce 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -135,6 +135,16 @@ static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val) return false; } +void pmp_unlock_entries(CPURISCVState *env) +{ + uint32_t pmp_num = pmp_get_num_rules(env); + int i; + + for (i = 0; i < pmp_num; i++) { + env->pmp_state.pmp[i].cfg_reg &= ~(PMP_LOCK | PMP_AMATCH); + } +} + static void pmp_decode_napot(target_ulong a, target_ulong *sa, target_ulong *ea) { diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h index cf5c99f8e6..9af8614cd4 100644 --- a/target/riscv/pmp.h +++ b/target/riscv/pmp.h @@ -28,6 +28,7 @@ typedef enum { PMP_READ = 1 << 0, PMP_WRITE = 1 << 1, PMP_EXEC = 1 << 2, + PMP_AMATCH = (3 << 3), PMP_LOCK = 1 << 7 } pmp_priv_t; @@ -81,6 +82,7 @@ void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index); void pmp_update_rule_nums(CPURISCVState *env); uint32_t pmp_get_num_rules(CPURISCVState *env); int pmp_priv_to_page_prot(pmp_priv_t pmp_priv); +void pmp_unlock_entries(CPURISCVState *env); #define MSECCFG_MML_ISSET(env) get_field(env->mseccfg, MSECCFG_MML) #define MSECCFG_MMWP_ISSET(env) get_field(env->mseccfg, MSECCFG_MMWP)