pmp_hart_has_privs decides the permissions of a byte range by testing only the two endpoint bytes against each PMP entry. An active entry lying strictly between the endpoints matches neither byte and is skipped, so a lower-priority entry silently grants an access that the higher-priority entry must deny.
Replace the endpoint sampling with interval tests, mirroring the predicate pmp_get_tlb_size already uses. Signed-off-by: Max Chou <[email protected]> --- target/riscv/tcg/pmp.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/target/riscv/tcg/pmp.c b/target/riscv/tcg/pmp.c index 41b55519a8e..94224920d8d 100644 --- a/target/riscv/tcg/pmp.c +++ b/target/riscv/tcg/pmp.c @@ -299,20 +299,6 @@ void pmp_update_rule_nums(CPURISCVState *env) } } -static int pmp_is_in_range(CPURISCVState *env, int pmp_index, hwaddr addr) -{ - int result = 0; - - if ((addr >= env->pmp_state.addr[pmp_index].sa) && - (addr <= env->pmp_state.addr[pmp_index].ea)) { - result = 1; - } else { - result = 0; - } - - return result; -} - /* * Check if the address has required RWX privs when no PMP entry is matched. */ @@ -387,8 +373,8 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr, { int i = 0; int pmp_size = 0; - hwaddr s = 0; - hwaddr e = 0; + hwaddr last = 0; + bool size_known = size != 0; uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions; /* Short cut if no rules */ @@ -414,12 +400,15 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr, * 1.10 draft priv spec states there is an implicit order * from low to high */ + last = addr + pmp_size - 1; + for (i = 0; i < pmp_regions; i++) { - s = pmp_is_in_range(env, i, addr); - e = pmp_is_in_range(env, i, addr + pmp_size - 1); + hwaddr sa = env->pmp_state.addr[i].sa; + hwaddr ea = env->pmp_state.addr[i].ea; + bool contains = (sa <= addr) && (last <= ea); + bool overlaps = (addr <= ea) && (sa <= last); - /* partially inside */ - if ((s + e) == 1) { + if (size_known && overlaps && !contains) { qemu_log_mask(LOG_GUEST_ERROR, "pmp violation - access is partially inside\n"); *allowed_privs = 0; @@ -430,7 +419,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr, const uint8_t a_field = pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg); - if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) { + if (contains && (PMP_AMATCH_OFF != a_field)) { /* * If the PMP entry is not off and the address is in range, * do the priv check -- 2.43.0
