Jay Chang <[email protected]> 於 2025年9月30日 週二 下午4:35寫道:
>
> This patch ensure pmpcfg and pmpaddr comply with WARL constraints.
>
> When the PMP granularity is greater than 4 bytes, NA4 mode is not valid
> per the spec and will be silently ignored.
>
> According to the spec, changing pmpcfg.A only affects the "read" value
> of pmpaddr. When G > 2 and pmpcfg.A is NAPOT, bits pmpaddr[G-2:0] read
> as all ones. When G > 1 and pmpcfg.A is OFF or TOR, bits pmpaddr[G-1:0]
> read as all zeros. This allows software to read back the correct
> granularity value.
>
> In addition, when updating the PMP address rule in TOR mode,
> the start and end addresses of the PMP region should be aligned
> to the PMP granularity. (The current SPEC only state in TOR mode
> that bits pmpaddr[G-1:0] do not affect the TOR address-matching logic.)
>
> Signed-off-by: Jay Chang <[email protected]>
> Reviewed-by: Frank Chang <[email protected]>
> Reviewed-by: Jim Shu <[email protected]>
> ---
> target/riscv/pmp.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 46 insertions(+)
>
> diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
> index 72f1372a49..d5cd76df3a 100644
> --- a/target/riscv/pmp.c
> +++ b/target/riscv/pmp.c
> @@ -108,6 +108,17 @@ static int pmp_is_invalid_smepmp_cfg(CPURISCVState *env,
> uint8_t val)
> 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.
> @@ -153,6 +164,15 @@ static bool pmp_write_cfg(CPURISCVState *env, uint32_t
> pmp_index, uint8_t val)
> 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;
> @@ -199,6 +219,7 @@ void pmp_update_rule_addr(CPURISCVState *env, uint32_t
> pmp_index)
> 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;
> @@ -211,6 +232,11 @@ void pmp_update_rule_addr(CPURISCVState *env, uint32_t
> pmp_index)
> break;
>
> case PMP_AMATCH_TOR:
> + /* Bits pmpaddr[G-1:0] do not affect the TOR address-matching logic.
> */
> + if (g >= 1) {
> + prev_addr &= ~((1UL << g) - 1UL);
> + this_addr &= ~((1UL << g) - 1UL);
> + }
> if (prev_addr >= this_addr) {
> sa = ea = 0u;
> break;
> @@ -577,6 +603,7 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t
> addr_index,
>
> /*
> * 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)
> {
> @@ -585,6 +612,25 @@ 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) {
> + val &= ~((1 << g) - 1);
You should use 1UL here, too, as val is target_ulong type.
> + }
> + break;
> + case PMP_AMATCH_NAPOT:
> + /* Bit [g-2:0] read all one */
> + if (g >= 2) {
> + val |= ((1 << (g - 1)) - 1);
Same here.
Regards,
Frank Chang
> + }
> + break;
> + default:
> + break;
> + }
> trace_pmpaddr_csr_read(env->mhartid, addr_index, val);
> } else {
> qemu_log_mask(LOG_GUEST_ERROR,
> --
> 2.48.1
>
>