riscv_cpu_tlb_fill() uses the `size` parameter to check PMP violation using pmp_hart_has_privs(). However, the size passed from tlb_fill(), which is called by get_page_addr_code(), is always a hard-coded value 0. This causes a false PMP violation if the instruction presents on a PMP boundary.
In order to fix, simply correct the size to 4 if the access_type is MMU_INST_FETCH. Signed-off-by: Dayeol Lee <day...@berkeley.edu> --- target/riscv/cpu.h | 1 + target/riscv/cpu_helper.c | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 0adb307f32..386c80e764 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -88,6 +88,7 @@ enum { #define MMU_USER_IDX 3 #define MAX_RISCV_PMPS (16) +#define RISCV_INSN_LENGTH 4 typedef struct CPURISCVState CPURISCVState; diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index e32b6126af..877e89dbf2 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -441,6 +441,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, CPURISCVState *env = &cpu->env; hwaddr pa = 0; int prot; + int pmp_size = 0; bool pmp_violation = false; int ret = TRANSLATE_FAIL; int mode = mmu_idx; @@ -460,9 +461,15 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, "%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx " prot %d\n", __func__, address, ret, pa, prot); + if (access_type == MMU_INST_FETCH) { + pmp_size = RISCV_INSN_LENGTH; + } else { + pmp_size = size; + } + if (riscv_feature(env, RISCV_FEATURE_PMP) && (ret == TRANSLATE_SUCCESS) && - !pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) { + !pmp_hart_has_privs(env, pa, pmp_size, 1 << access_type, mode)) { ret = TRANSLATE_PMP_FAIL; } if (ret == TRANSLATE_PMP_FAIL) { -- 2.20.1