qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PULL v3 24/42] target/riscv: Implementation of enhanced PMP (ePMP)


From: Peter Maydell
Subject: Re: [PULL v3 24/42] target/riscv: Implementation of enhanced PMP (ePMP)
Date: Thu, 20 May 2021 14:51:10 +0100

On Tue, 11 May 2021 at 11:21, Alistair Francis <alistair.francis@wdc.com> wrote:
>
> From: Hou Weiying <weiying_hou@outlook.com>
>
> This commit adds support for ePMP v0.9.1.
>
> The ePMP spec can be found in:
> https://docs.google.com/document/d/1Mh_aiHYxemL0umN3GTTw8vsbmzHZ_nxZXgjgOUzbvc8
>
> Signed-off-by: Hongzheng-Li <Ethan.Lee.QNL@gmail.com>
> Signed-off-by: Hou Weiying <weiying_hou@outlook.com>
> Signed-off-by: Myriad-Dreamin <camiyoru@gmail.com>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> Message-id: 
> fef23b885f9649a4d54e7c98b168bdec5d297bb1.1618812899.git.alistair.francis@wdc.com
> [ Changes by AF:
>  - Rebase on master
>  - Update to latest spec
>  - Use a switch case to handle ePMP MML permissions
>  - Fix a few bugs
> ]
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Hi; this code confuses Coverity into thinking that the pmp_hart_has_privs()
function might read the value pointed to by 'allowed_privs' when
it is uninitialized (CID 1453108):


> @@ -294,13 +351,94 @@ bool pmp_hart_has_privs(CPURISCVState *env, 
> target_ulong addr,
>              pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
>
>          /*
> -         * If the PMP entry is not off and the address is in range, do the 
> priv
> -         * check
> +         * Convert the PMP permissions to match the truth table in the
> +         * ePMP spec.
>           */
> +        const uint8_t epmp_operation =
> +            ((env->pmp_state.pmp[i].cfg_reg & PMP_LOCK) >> 4) |
> +            ((env->pmp_state.pmp[i].cfg_reg & PMP_READ) << 2) |
> +            (env->pmp_state.pmp[i].cfg_reg & PMP_WRITE) |
> +            ((env->pmp_state.pmp[i].cfg_reg & PMP_EXEC) >> 2);

Here we construct a value which can only be in the range [0,15],
but we do it in a way that Coverity isn't clever enough to figure out...

> +
>          if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
> -            *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;
> +            /*
> +             * If the PMP entry is not off and the address is in range,
> +             * do the priv check
> +             */
> +            if (!MSECCFG_MML_ISSET(env)) {
> +                /*
> +                 * If mseccfg.MML Bit is not set, do pmp priv check
> +                 * This will always apply to regular PMP.
> +                 */
> +                *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;
> +                }
> +            } else {
> +                /*
> +                 * If mseccfg.MML Bit set, do the enhanced pmp priv check
> +                 */
> +                if (mode == PRV_M) {
> +                    switch (epmp_operation) {
> +                    case 0:
> +                    case 1:
> +                    case 4:
> +                    case 5:
> +                    case 6:
> +                    case 7:
> +                    case 8:
> +                        *allowed_privs = 0;
> +                        break;
> +                    case 2:
> +                    case 3:
> +                    case 14:
> +                        *allowed_privs = PMP_READ | PMP_WRITE;
> +                        break;
> +                    case 9:
> +                    case 10:
> +                        *allowed_privs = PMP_EXEC;
> +                        break;
> +                    case 11:
> +                    case 13:
> +                        *allowed_privs = PMP_READ | PMP_EXEC;
> +                        break;
> +                    case 12:
> +                    case 15:
> +                        *allowed_privs = PMP_READ;
> +                        break;

...so coverity thinks that "via the 'default' case" is a valid flow
of control in these switch() statements...

> +                    }
> +                } else {
> +                    switch (epmp_operation) {
> +                    case 0:
> +                    case 8:
> +                    case 9:
> +                    case 12:
> +                    case 13:
> +                    case 14:
> +                        *allowed_privs = 0;
> +                        break;
> +                    case 1:
> +                    case 10:
> +                    case 11:
> +                        *allowed_privs = PMP_EXEC;
> +                        break;
> +                    case 2:
> +                    case 4:
> +                    case 15:
> +                        *allowed_privs = PMP_READ;
> +                        break;
> +                    case 3:
> +                    case 6:
> +                        *allowed_privs = PMP_READ | PMP_WRITE;
> +                        break;
> +                    case 5:
> +                        *allowed_privs = PMP_READ | PMP_EXEC;
> +                        break;
> +                    case 7:
> +                        *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
> +                        break;
> +                    }
> +                }
>              }
>
>              ret = ((privs & *allowed_privs) == privs);

...and that we can get to here without having ever set *allowed_privs.


Adding
   default:
       g_assert_not_reached();

to both switches should clarify to both Coverity and human readers that
the cases in the switch are a complete enumeration of the possibilities.

thanks
-- PMM



reply via email to

[Prev in Thread] Current Thread [Next in Thread]