|
@@ -75,6 +75,44 @@ static int pmp_is_readonly(CPURISCVState *env, uint32_t pmp_index)
|
|
return pmp_is_locked(env, pmp_index) && !MSECCFG_RLB_ISSET(env);
|
|
return pmp_is_locked(env, pmp_index) && !MSECCFG_RLB_ISSET(env);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Check whether `val` is an invalid Smepmp config value
|
|
|
|
+ */
|
|
|
|
+static int pmp_is_invalid_smepmp_cfg(CPURISCVState *env, uint8_t val)
|
|
|
|
+{
|
|
|
|
+ /* No check if mseccfg.MML is not set or if mseccfg.RLB is set */
|
|
|
|
+ if (!MSECCFG_MML_ISSET(env) || MSECCFG_RLB_ISSET(env)) {
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Adding a rule with executable privileges that either is M-mode-only
|
|
|
|
+ * or a locked Shared-Region is not possible
|
|
|
|
+ */
|
|
|
|
+ switch (pmp_get_smepmp_operation(val)) {
|
|
|
|
+ case 0:
|
|
|
|
+ case 1:
|
|
|
|
+ case 2:
|
|
|
|
+ case 3:
|
|
|
|
+ case 4:
|
|
|
|
+ case 5:
|
|
|
|
+ case 6:
|
|
|
|
+ case 7:
|
|
|
|
+ case 8:
|
|
|
|
+ case 12:
|
|
|
|
+ case 14:
|
|
|
|
+ case 15:
|
|
|
|
+ return 0;
|
|
|
|
+ case 9:
|
|
|
|
+ case 10:
|
|
|
|
+ case 11:
|
|
|
|
+ case 13:
|
|
|
|
+ return 1;
|
|
|
|
+ default:
|
|
|
|
+ g_assert_not_reached();
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Count the number of active rules.
|
|
* Count the number of active rules.
|
|
*/
|
|
*/
|
|
@@ -103,44 +141,13 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index)
|
|
static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
|
|
static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
|
|
{
|
|
{
|
|
if (pmp_index < MAX_RISCV_PMPS) {
|
|
if (pmp_index < MAX_RISCV_PMPS) {
|
|
- bool readonly = true;
|
|
|
|
-
|
|
|
|
- if (riscv_cpu_cfg(env)->ext_smepmp) {
|
|
|
|
- /* mseccfg.RLB is set */
|
|
|
|
- if (MSECCFG_RLB_ISSET(env)) {
|
|
|
|
- readonly = false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* mseccfg.MML is not set */
|
|
|
|
- if (!MSECCFG_MML_ISSET(env) && !pmp_is_readonly(env, pmp_index)) {
|
|
|
|
- readonly = false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* mseccfg.MML is set */
|
|
|
|
- if (MSECCFG_MML_ISSET(env)) {
|
|
|
|
- /* not adding execute bit */
|
|
|
|
- if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) {
|
|
|
|
- readonly = false;
|
|
|
|
- }
|
|
|
|
- /* shared region and not adding X bit */
|
|
|
|
- if ((val & PMP_LOCK) != PMP_LOCK &&
|
|
|
|
- (val & 0x7) != (PMP_WRITE | PMP_EXEC)) {
|
|
|
|
- readonly = false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- readonly = pmp_is_readonly(env, pmp_index);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (readonly) {
|
|
|
|
|
|
+ if (pmp_is_readonly(env, pmp_index)) {
|
|
qemu_log_mask(LOG_GUEST_ERROR,
|
|
qemu_log_mask(LOG_GUEST_ERROR,
|
|
"ignoring pmpcfg write - read only\n");
|
|
"ignoring pmpcfg write - read only\n");
|
|
- } else if (env->pmp_state.pmp[pmp_index].cfg_reg != val) {
|
|
|
|
- /* If !mseccfg.MML then ignore writes with encoding RW=01 */
|
|
|
|
- if ((val & PMP_WRITE) && !(val & PMP_READ) &&
|
|
|
|
- !MSECCFG_MML_ISSET(env)) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
|
|
+ } else if (pmp_is_invalid_smepmp_cfg(env, val)) {
|
|
|
|
+ qemu_log_mask(LOG_GUEST_ERROR,
|
|
|
|
+ "ignoring pmpcfg write - invalid\n");
|
|
|
|
+ } else {
|
|
env->pmp_state.pmp[pmp_index].cfg_reg = val;
|
|
env->pmp_state.pmp[pmp_index].cfg_reg = val;
|
|
pmp_update_rule_addr(env, pmp_index);
|
|
pmp_update_rule_addr(env, pmp_index);
|
|
return true;
|
|
return true;
|