diff options
author | Jim Shu <cwshu@andestech.com> | 2021-02-21 22:01:20 +0800 |
---|---|---|
committer | Alistair Francis <alistair.francis@wdc.com> | 2021-03-22 21:54:40 -0400 |
commit | b297129ae19e26d3cc0e376d2bfc33d76b06d83b (patch) | |
tree | ab5fd1bf4ebf1dab6b38e9b84ae6d253588495f5 /target/riscv/pmp.c | |
parent | 82a4ed8e5014ee814c63be33987e6783d5eacce2 (diff) |
target/riscv: propagate PMP permission to TLB page
Currently, PMP permission checking of TLB page is bypassed if TLB hits
Fix it by propagating PMP permission to TLB page permission.
PMP permission checking also use MMU-style API to change TLB permission
and size.
Signed-off-by: Jim Shu <cwshu@andestech.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-id: 1613916082-19528-2-git-send-email-cwshu@andestech.com
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Diffstat (limited to 'target/riscv/pmp.c')
-rw-r--r-- | target/riscv/pmp.c | 80 |
1 files changed, 59 insertions, 21 deletions
diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 80d0334e1b..ebd874cde3 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -217,6 +217,35 @@ static int pmp_is_in_range(CPURISCVState *env, int pmp_index, target_ulong addr) return result; } +/* + * Check if the address has required RWX privs when no PMP entry is matched. + */ +static bool pmp_hart_has_privs_default(CPURISCVState *env, target_ulong addr, + target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs, + target_ulong mode) +{ + bool ret; + + if ((!riscv_feature(env, RISCV_FEATURE_PMP)) || (mode == PRV_M)) { + /* + * Privileged spec v1.10 states if HW doesn't implement any PMP entry + * or no PMP entry matches an M-Mode access, the access succeeds. + */ + ret = true; + *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC; + } else { + /* + * Other modes are not allowed to succeed if they don't * match a rule, + * but there are rules. We've checked for no rule earlier in this + * function. + */ + ret = false; + *allowed_privs = 0; + } + + return ret; +} + /* * Public Interface @@ -226,18 +255,19 @@ static int pmp_is_in_range(CPURISCVState *env, int pmp_index, target_ulong addr) * Check if the address has required RWX privs to complete desired operation */ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, - target_ulong size, pmp_priv_t privs, target_ulong mode) + target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs, + target_ulong mode) { int i = 0; int ret = -1; int pmp_size = 0; target_ulong s = 0; target_ulong e = 0; - pmp_priv_t allowed_privs = 0; /* Short cut if no rules */ if (0 == pmp_get_num_rules(env)) { - return (env->priv == PRV_M) ? true : false; + return pmp_hart_has_privs_default(env, addr, size, privs, + allowed_privs, mode); } if (size == 0) { @@ -277,37 +307,25 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, * check */ if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) { - allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC; + *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC; if ((mode != PRV_M) || pmp_is_locked(env, i)) { - allowed_privs &= env->pmp_state.pmp[i].cfg_reg; + *allowed_privs &= env->pmp_state.pmp[i].cfg_reg; } - if ((privs & allowed_privs) == privs) { - ret = 1; - break; - } else { - ret = 0; - break; - } + ret = ((privs & *allowed_privs) == privs); + break; } } /* No rule matched */ if (ret == -1) { - if (mode == PRV_M) { - ret = 1; /* Privileged spec v1.10 states if no PMP entry matches an - * M-Mode access, the access succeeds */ - } else { - ret = 0; /* Other modes are not allowed to succeed if they don't - * match a rule, but there are rules. We've checked for - * no rule earlier in this function. */ - } + return pmp_hart_has_privs_default(env, addr, size, privs, + allowed_privs, mode); } return ret == 1 ? true : false; } - /* * Handle a write to a pmpcfg CSP */ @@ -442,3 +460,23 @@ bool pmp_is_range_in_tlb(CPURISCVState *env, hwaddr tlb_sa, return false; } + +/* + * Convert PMP privilege to TLB page privilege. + */ +int pmp_priv_to_page_prot(pmp_priv_t pmp_priv) +{ + int prot = 0; + + if (pmp_priv & PMP_READ) { + prot |= PAGE_READ; + } + if (pmp_priv & PMP_WRITE) { + prot |= PAGE_WRITE; + } + if (pmp_priv & PMP_EXEC) { + prot |= PAGE_EXEC; + } + + return prot; +} |