Signed-off-by: Luis Cunha <[email protected]>
---
target/riscv/cpu.c | 8 ++++++++
target/riscv/cpu.h | 2 ++
target/riscv/cpu_bits.h | 2 ++
target/riscv/cpu_cfg_fields.h.inc | 1 +
target/riscv/csr.c | 27 +++++++++++++++++++++++++++
target/riscv/pmp.c | 14 +++++++++++++-
target/riscv/pmp.h | 1 +
7 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index e56470a374..5383e07dbd 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -760,6 +760,14 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType
type)
}
pmp_unlock_entries(env);
+
+ /* Is SPMP enabled? */
+ if (riscv_cpu_cfg(env)->spmp) {
+ env->mpmpdeleg = MPMP_DELEG_DEFAULT;
+ env->spmp_state.num_deleg_rules = 64 - MPMP_DELEG_DEFAULT;
+
+ spmp_unlock_entries(env);
+ }
#else
env->priv = PRV_U;
env->senvcfg = 0;
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index c265098324..e19c1216ea 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -179,6 +179,7 @@ extern RISCVCPUImpliedExtsRule
*riscv_multi_ext_implied_rules[];
#define MIN_RISCV_PMP_GRANULARITY 4
#define MAX_RISCV_SPMPS (64)
+#define MPMP_DELEG_DEFAULT (64)
#if !defined(CONFIG_USER_ONLY)
#include "pmp.h"
@@ -447,6 +448,7 @@ struct CPUArchState {
/* S-mode Physical Memory Protection */
spmp_table_t spmp_state;
+ uint16_t mpmpdeleg;
/* trigger module */
target_ulong trigger_cur;
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 9b7ab28bba..36f7c1e873 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -449,6 +449,8 @@
#define CSR_PMPADDR62 0x3ee
#define CSR_PMPADDR63 0x3ef
+#define CSR_MPMPDELEG 0x316
+
/* RNMI */
#define CSR_MNSCRATCH 0x740
#define CSR_MNEPC 0x741
diff --git a/target/riscv/cpu_cfg_fields.h.inc
b/target/riscv/cpu_cfg_fields.h.inc
index 72d417c241..772cc176d0 100644
--- a/target/riscv/cpu_cfg_fields.h.inc
+++ b/target/riscv/cpu_cfg_fields.h.inc
@@ -119,6 +119,7 @@ BOOL_FIELD(rvv_ta_all_1s)
BOOL_FIELD(rvv_ma_all_1s)
BOOL_FIELD(rvv_vl_half_avl)
BOOL_FIELD(rvv_vsetvl_x0_vill)
+BOOL_FIELD(ext_smpmpdeleg)
/* Named features */
BOOL_FIELD(ext_svade)
BOOL_FIELD(ext_zic64b)
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 167d84d92a..4b9fa11540 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -5365,6 +5365,30 @@ static int rmw_xireg_spmp(CPURISCVState *env, int csrno,
return 0;
}
+/* S-mode Physical Memory Protection */
+static RISCVException rmw_mpmpdeleg(CPURISCVState *env, int csrno,
+ target_ulong *ret_val,
+ target_ulong new_val, target_ulong wr_mask)
+{
+ uint16_t new_mpmpdeleg = (env->mpmpdeleg & ~wr_mask) | (new_val & wr_mask);
+
+ if (ret_val) {
+ *ret_val = env->mpmpdeleg;
+ }
+
+ /*
+ * pmpnum is locked if MSECCFG_MML is set
+ * and if new_mpmpdeleg is higher than last locked rule
+ */
+ if (!(env->mseccfg & MSECCFG_MML) &&
+ (new_mpmpdeleg & 0x7F) > env->pmp_state.last_locked_rule) {
+ env->mpmpdeleg = new_mpmpdeleg & 0x7F;
+ }
+
+ env->spmp_state.num_deleg_rules = MPMP_DELEG_DEFAULT - env->mpmpdeleg;
+ return RISCV_EXCP_NONE;
+}
+
static RISCVException read_tselect(CPURISCVState *env, int csrno,
target_ulong *val)
{
@@ -6362,6 +6386,9 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_PMPADDR63] = { "pmpaddr63", pmp, read_pmpaddr, write_pmpaddr,
.min_priv_ver = PRIV_VERSION_1_12_0 },
+ /* S-mode Physical Memory Protection */
+ [CSR_MPMPDELEG] = { "mpmpdeleg", spmp, NULL, NULL, rmw_mpmpdeleg },
+
/* Debug CSRs */
[CSR_TSELECT] = { "tselect", debug, read_tselect, write_tselect },
[CSR_TDATA1] = { "tdata1", debug, read_tdata, write_tdata },
diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 3ef62d26ad..22d6f1f5b3 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -174,6 +174,12 @@ static bool pmp_write_cfg(CPURISCVState *env, uint32_t
pmp_index, uint8_t val)
return false;
}
env->pmp_state.pmp[pmp_index].cfg_reg = val;
+
+ if ((val & PMP_LOCK) &&
+ env->pmp_state.last_locked_rule < (signed int)pmp_index) {
+ env->pmp_state.last_locked_rule = pmp_index;
+ }
+
pmp_update_rule_addr(env, pmp_index);
return true;
}
@@ -193,6 +199,8 @@ void pmp_unlock_entries(CPURISCVState *env)
for (i = 0; i < pmp_num; i++) {
env->pmp_state.pmp[i].cfg_reg &= ~(PMP_LOCK | PMP_AMATCH);
}
+
+ env->pmp_state.last_locked_rule = -1;
}
static void pmp_decode_napot(hwaddr a, hwaddr *sa, hwaddr *ea)
@@ -385,11 +393,15 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
pmp_size = size;
}
+ /* If SPMP is enabled, use the MPMP delegation */
+ uint8_t max_pmp_index =
+ (riscv_cpu_cfg(env)->spmp) ? (env->mpmpdeleg & 0x7F) : pmp_regions;
+
/*
* 1.10 draft priv spec states there is an implicit order
* from low to high
*/
- for (i = 0; i < pmp_regions; i++) {
+ for (i = 0; i < max_pmp_index; i++) {
s = pmp_is_in_range(env, i, addr);
e = pmp_is_in_range(env, i, addr + pmp_size - 1);
diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h
index 271cf24169..3194c6b531 100644
--- a/target/riscv/pmp.h
+++ b/target/riscv/pmp.h
@@ -63,6 +63,7 @@ typedef struct {
pmp_entry_t pmp[MAX_RISCV_PMPS];
pmp_addr_t addr[MAX_RISCV_PMPS];
uint32_t num_rules;
+ signed char last_locked_rule;
} pmp_table_t;
void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
--
2.43.0