From e54d0916ef890b70e7d9e1f2e7e02645a5754572 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Mon, 8 Mar 2021 15:39:46 -0500 Subject: [PATCH] target/riscv/pmp: Raise exception if no PMP entry is configured As per the privilege specification, any access from S/U mode should fail if no pmp region is configured. Backports d102f19a2085ac931cb998e6153b73248cca49f1 --- qemu/header_gen.py | 2 ++ qemu/riscv32.h | 2 ++ qemu/riscv64.h | 2 ++ qemu/target/riscv/op_helper.c | 5 +++++ qemu/target/riscv/pmp.c | 18 ++++++++++++++++-- qemu/target/riscv/pmp.h | 3 +++ 6 files changed, 30 insertions(+), 2 deletions(-) diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 93c02627..c7c6d079 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -7311,7 +7311,9 @@ riscv_symbols = ( 'helper_vcompress_vm_w', 'helper_vcompress_vm_d', 'pmp_hart_has_privs', + 'pmp_get_num_rules', 'pmp_is_range_in_tlb', + 'pmp_update_rule_nums', 'pmpaddr_csr_read', 'pmpaddr_csr_write', 'pmpcfg_csr_read', diff --git a/qemu/riscv32.h b/qemu/riscv32.h index 671bc4bf..e5157a99 100644 --- a/qemu/riscv32.h +++ b/qemu/riscv32.h @@ -4747,7 +4747,9 @@ #define helper_vcompress_vm_w helper_vcompress_vm_w_riscv32 #define helper_vcompress_vm_d helper_vcompress_vm_d_riscv32 #define pmp_hart_has_privs pmp_hart_has_privs_riscv32 +#define pmp_get_num_rules pmp_get_num_rules_riscv32 #define pmp_is_range_in_tlb pmp_is_range_in_tlb_riscv32 +#define pmp_update_rule_nums pmp_update_rule_nums_riscv32 #define pmpaddr_csr_read pmpaddr_csr_read_riscv32 #define pmpaddr_csr_write pmpaddr_csr_write_riscv32 #define pmpcfg_csr_read pmpcfg_csr_read_riscv32 diff --git a/qemu/riscv64.h b/qemu/riscv64.h index 70336c6f..8b9e4e8c 100644 --- a/qemu/riscv64.h +++ b/qemu/riscv64.h @@ -4747,7 +4747,9 @@ #define helper_vcompress_vm_w helper_vcompress_vm_w_riscv64 #define helper_vcompress_vm_d helper_vcompress_vm_d_riscv64 #define pmp_hart_has_privs pmp_hart_has_privs_riscv64 +#define pmp_get_num_rules pmp_get_num_rules_riscv64 #define pmp_is_range_in_tlb pmp_is_range_in_tlb_riscv64 +#define pmp_update_rule_nums pmp_update_rule_nums_riscv64 #define pmpaddr_csr_read pmpaddr_csr_read_riscv64 #define pmpaddr_csr_write pmpaddr_csr_write_riscv64 #define pmpcfg_csr_read pmpcfg_csr_read_riscv64 diff --git a/qemu/target/riscv/op_helper.c b/qemu/target/riscv/op_helper.c index 5558e654..a64bb24a 100644 --- a/qemu/target/riscv/op_helper.c +++ b/qemu/target/riscv/op_helper.c @@ -150,6 +150,11 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb) uint64_t mstatus = env->mstatus; target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP); + + if (!pmp_get_num_rules(env) && (prev_priv != PRV_M)) { + riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); + } + target_ulong prev_virt = get_field(env->mstatus, MSTATUS_MPV); mstatus = set_field(mstatus, MSTATUS_MIE, get_field(mstatus, MSTATUS_MPIE)); diff --git a/qemu/target/riscv/pmp.c b/qemu/target/riscv/pmp.c index dcf16492..dd118348 100644 --- a/qemu/target/riscv/pmp.c +++ b/qemu/target/riscv/pmp.c @@ -84,7 +84,7 @@ static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index) /* * Count the number of active rules. */ -static inline uint32_t pmp_get_num_rules(CPURISCVState *env) +uint32_t pmp_get_num_rules(CPURISCVState *env) { return env->pmp_state.num_rules; } @@ -147,6 +147,20 @@ static void pmp_decode_napot(target_ulong a, target_ulong *sa, target_ulong *ea) } +void pmp_update_rule_nums(CPURISCVState *env) +{ + int i; + + env->pmp_state.num_rules = 0; + for (i = 0; i < MAX_RISCV_PMPS; i++) { + const uint8_t a_field = + pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg); + if (PMP_AMATCH_OFF != a_field) { + env->pmp_state.num_rules++; + } + } +} + /* Convert cfg/addr reg values here into simple 'sa' --> start address and 'ea' * end address values. * This function is called relatively infrequently whereas the check that @@ -239,7 +253,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, /* Short cut if no rules */ if (0 == pmp_get_num_rules(env)) { - return true; + return (env->priv == PRV_M) ? true : false; } /* 1.10 draft priv spec states there is an implicit order diff --git a/qemu/target/riscv/pmp.h b/qemu/target/riscv/pmp.h index 6a8f0728..6e89c8e3 100644 --- a/qemu/target/riscv/pmp.h +++ b/qemu/target/riscv/pmp.h @@ -63,4 +63,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, bool pmp_is_range_in_tlb(CPURISCVState *env, hwaddr tlb_sa, target_ulong *tlb_size); +void pmp_update_rule_nums(CPURISCVState *env); +uint32_t pmp_get_num_rules(CPURISCVState *env); + #endif