Skip to content

Commit f82dd28

Browse files
loiclefortMichael Tokarev
authored andcommitted
target/riscv: pmp: don't allow RLB to bypass rule privileges
When Smepmp is supported, mseccfg.RLB allows bypassing locks when writing CSRs but should not affect interpretation of actual PMP rules. This is not the case with the current implementation where pmp_hart_has_privs calls pmp_is_locked which implements mseccfg.RLB bypass. This commit implements the correct behavior by removing mseccfg.RLB bypass from pmp_is_locked. RLB bypass when writing CSRs is implemented by adding a new pmp_is_readonly function that calls pmp_is_locked and check mseccfg.RLB. pmp_write_cfg and pmpaddr_csr_write are changed to use this new function. Signed-off-by: Loïc Lefort <[email protected]> Reviewed-by: Alistair Francis <[email protected]> Reviewed-by: Daniel Henrique Barboza <[email protected]> Reviewed-by: LIU Zhiwei  <[email protected]> Message-ID: <[email protected]> Signed-off-by: Alistair Francis <[email protected]> Cc: [email protected] (cherry picked from commit 4541d20) Signed-off-by: Michael Tokarev <[email protected]>
1 parent 1514381 commit f82dd28

File tree

1 file changed

+23
-20
lines changed

1 file changed

+23
-20
lines changed

target/riscv/pmp.c

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,6 @@ static inline uint8_t pmp_get_a_field(uint8_t cfg)
4545
*/
4646
static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index)
4747
{
48-
/* mseccfg.RLB is set */
49-
if (MSECCFG_RLB_ISSET(env)) {
50-
return 0;
51-
}
52-
5348
if (env->pmp_state.pmp[pmp_index].cfg_reg & PMP_LOCK) {
5449
return 1;
5550
}
@@ -62,6 +57,15 @@ static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index)
6257
return 0;
6358
}
6459

60+
/*
61+
* Check whether a PMP is locked for writing or not.
62+
* (i.e. has LOCK flag and mseccfg.RLB is unset)
63+
*/
64+
static int pmp_is_readonly(CPURISCVState *env, uint32_t pmp_index)
65+
{
66+
return pmp_is_locked(env, pmp_index) && !MSECCFG_RLB_ISSET(env);
67+
}
68+
6569
/*
6670
* Count the number of active rules.
6771
*/
@@ -90,39 +94,38 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index)
9094
static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
9195
{
9296
if (pmp_index < MAX_RISCV_PMPS) {
93-
bool locked = true;
97+
bool readonly = true;
9498

9599
if (riscv_cpu_cfg(env)->ext_smepmp) {
96100
/* mseccfg.RLB is set */
97101
if (MSECCFG_RLB_ISSET(env)) {
98-
locked = false;
102+
readonly = false;
99103
}
100104

101105
/* mseccfg.MML is not set */
102-
if (!MSECCFG_MML_ISSET(env) && !pmp_is_locked(env, pmp_index)) {
103-
locked = false;
106+
if (!MSECCFG_MML_ISSET(env) && !pmp_is_readonly(env, pmp_index)) {
107+
readonly = false;
104108
}
105109

106110
/* mseccfg.MML is set */
107111
if (MSECCFG_MML_ISSET(env)) {
108112
/* not adding execute bit */
109113
if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) {
110-
locked = false;
114+
readonly = false;
111115
}
112116
/* shared region and not adding X bit */
113117
if ((val & PMP_LOCK) != PMP_LOCK &&
114118
(val & 0x7) != (PMP_WRITE | PMP_EXEC)) {
115-
locked = false;
119+
readonly = false;
116120
}
117121
}
118122
} else {
119-
if (!pmp_is_locked(env, pmp_index)) {
120-
locked = false;
121-
}
123+
readonly = pmp_is_readonly(env, pmp_index);
122124
}
123125

124-
if (locked) {
125-
qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n");
126+
if (readonly) {
127+
qemu_log_mask(LOG_GUEST_ERROR,
128+
"ignoring pmpcfg write - read only\n");
126129
} else if (env->pmp_state.pmp[pmp_index].cfg_reg != val) {
127130
/* If !mseccfg.MML then ignore writes with encoding RW=01 */
128131
if ((val & PMP_WRITE) && !(val & PMP_READ) &&
@@ -524,14 +527,14 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
524527
uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg;
525528
is_next_cfg_tor = PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg);
526529

527-
if (pmp_is_locked(env, addr_index + 1) && is_next_cfg_tor) {
530+
if (pmp_is_readonly(env, addr_index + 1) && is_next_cfg_tor) {
528531
qemu_log_mask(LOG_GUEST_ERROR,
529-
"ignoring pmpaddr write - pmpcfg + 1 locked\n");
532+
"ignoring pmpaddr write - pmpcfg+1 read only\n");
530533
return;
531534
}
532535
}
533536

534-
if (!pmp_is_locked(env, addr_index)) {
537+
if (!pmp_is_readonly(env, addr_index)) {
535538
if (env->pmp_state.pmp[addr_index].addr_reg != val) {
536539
env->pmp_state.pmp[addr_index].addr_reg = val;
537540
pmp_update_rule_addr(env, addr_index);
@@ -542,7 +545,7 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
542545
}
543546
} else {
544547
qemu_log_mask(LOG_GUEST_ERROR,
545-
"ignoring pmpaddr write - locked\n");
548+
"ignoring pmpaddr write - read only\n");
546549
}
547550
} else {
548551
qemu_log_mask(LOG_GUEST_ERROR,

0 commit comments

Comments
 (0)