g_assert_not_reached();
}
}
+/*
+ * Calculate PMP granularity value 'g'
+ *
+ * The granularity value 'g' is defined as log2(granularity) - 2, where
+ * granularity is the minimum alignment requirement for PMP regions in bytes.
+ */
+static inline int pmp_get_granularity_g(CPURISCVState *env)
+{
+ return __builtin_ctz(riscv_cpu_cfg(env)->pmp_granularity >> 2);
+}
+
/*
* Count the number of active rules.
qemu_log_mask(LOG_GUEST_ERROR,
"ignoring pmpcfg write - invalid\n");
} else {
+ uint8_t a_field = pmp_get_a_field(val);
+ /*
+ * When granularity g >= 1 (i.e., granularity > 4 bytes),
+ * the NA4 (Naturally Aligned 4-byte) mode is not selectable
+ */
+ if ((riscv_cpu_cfg(env)->pmp_granularity >
+ MIN_RISCV_PMP_GRANULARITY) && (a_field == PMP_AMATCH_NA4)) {
+ return false;
+ }
env->pmp_state.pmp[pmp_index].cfg_reg = val;
pmp_update_rule_addr(env, pmp_index);
return true;
target_ulong prev_addr = 0u;
hwaddr sa = 0u;
hwaddr ea = 0u;
+ int g = pmp_get_granularity_g(env);
if (pmp_index >= 1u) {
prev_addr = env->pmp_state.pmp[pmp_index - 1].addr_reg;
break;
case PMP_AMATCH_TOR:
+ /* Bits pmpaddr[G-1:0] do not affect the TOR address-matching logic. */
+ if (g >= 1) {
+ prev_addr &= ~((1ULL << g) - 1ULL);
+ this_addr &= ~((1ULL << g) - 1ULL);
+ }
if (prev_addr >= this_addr) {
sa = ea = 0u;
break;
/*
* Handle a read from a pmpaddr CSR
+ * Change A field of pmpcfg affects the read value of pmpaddr
*/
target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index)
{
if (addr_index < pmp_regions) {
val = env->pmp_state.pmp[addr_index].addr_reg;
+ int g = pmp_get_granularity_g(env);
+ switch (pmp_get_a_field(env->pmp_state.pmp[addr_index].cfg_reg)) {
+ case PMP_AMATCH_OFF:
+ /* fallthrough */
+ case PMP_AMATCH_TOR:
+ /* Bit [g-1:0] read all zero */
+ if (g >= 1 && g < TARGET_LONG_BITS) {
+ val &= ~((1ULL << g) - 1ULL);
+ }
+ break;
+ case PMP_AMATCH_NAPOT:
+ /* Bit [g-2:0] read all one */
+ if (g >= 2 && g < TARGET_LONG_BITS) {
+ val |= ((1ULL << (g - 1)) - 1ULL);
+ }
+ break;
+ default:
+ break;
+ }
trace_pmpaddr_csr_read(env->mhartid, addr_index, val);
} else {
qemu_log_mask(LOG_GUEST_ERROR,