qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH v2 11/35] target-arm: Split cpreg access checks


From: Peter Crosthwaite
Subject: Re: [Qemu-devel] [PATCH v2 11/35] target-arm: Split cpreg access checks out from read/write functions
Date: Tue, 11 Feb 2014 16:13:05 +1000

On Sat, Feb 1, 2014 at 1:45 AM, Peter Maydell <address@hidden> wrote:
> Several of the system registers handled via the ARMCPRegInfo
> mechanism have access trap control bits controlling whether the
> registers are accessible to lower privilege levels. Replace
> the existing mechanism (allowing the read and write functions
> to return EXCP_UDEF if access is denied) with a dedicated
> "check access rights" function pointer in the ARMCPRegInfo.
> This will allow us to simplify some of the register definitions,
> which no longer need read/write functions purely to handle
> the access checks.
>
> We take the opportunity to define the return value from the
> access checking function in a way that allows us to set the
> correct exception syndrome information for exceptions taken
> to AArch64 (which may need to distinguish access failures due
> to a configurable trap or enable from other kinds of access
> failure).
>
> This commit defines the new mechanism but does not move any
> of the registers across to use it.
>
> Signed-off-by: Peter Maydell <address@hidden>

Reviewed-by: Peter Crosthwaite <address@hidden>

> ---
>  target-arm/cpu.h           | 29 +++++++++++++++++++++++++----
>  target-arm/helper.h        |  1 +
>  target-arm/op_helper.c     | 18 ++++++++++++++++++
>  target-arm/translate-a64.c | 11 +++++++++++
>  target-arm/translate.c     | 11 +++++++++++
>  5 files changed, 66 insertions(+), 4 deletions(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index e66d464..30b1a1c 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -812,14 +812,29 @@ static inline int arm_current_pl(CPUARMState *env)
>
>  typedef struct ARMCPRegInfo ARMCPRegInfo;
>
> -/* Access functions for coprocessor registers. These should return
> - * 0 on success, or one of the EXCP_* constants if access should cause
> - * an exception (in which case *value is not written).
> - */
> +typedef enum CPAccessResult {
> +    /* Access is permitted */
> +    CP_ACCESS_OK = 0,
> +    /* Access fails due to a configurable trap or enable which would
> +     * result in a categorized exception syndrome giving information about
> +     * the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6,
> +     * 0xc or 0x18).
> +     */
> +    CP_ACCESS_TRAP = 1,
> +    /* Access fails and results in an exception syndrome 0x0 
> ("uncategorized").
> +     * Note that this is not a catch-all case -- the set of cases which may
> +     * result in this failure is specifically defined by the architecture.
> +     */
> +    CP_ACCESS_TRAP_UNCATEGORIZED = 2,
> +} CPAccessResult;
> +
> +/* Access functions for coprocessor registers. These should always succeed. 
> */
>  typedef int CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque,
>                       uint64_t *value);
>  typedef int CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque,
>                        uint64_t value);
> +/* Access permission check functions for coprocessor registers. */
> +typedef CPAccessResult CPAccessFn(CPUARMState *env, const ARMCPRegInfo 
> *opaque);
>  /* Hook function for register reset */
>  typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque);
>
> @@ -873,6 +888,12 @@ struct ARMCPRegInfo {
>       *  2. both readfn and writefn are specified
>       */
>      ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */
> +    /* Function for making any access checks for this register in addition to
> +     * those specified by the 'access' permissions bits. If NULL, no extra
> +     * checks required. The access check is performed at runtime, not at
> +     * translate time.
> +     */
> +    CPAccessFn *accessfn;
>      /* Function for handling reads of this register. If NULL, then reads
>       * will be done by loading from the offset into CPUARMState specified
>       * by fieldoffset.
> diff --git a/target-arm/helper.h b/target-arm/helper.h
> index 93a27ce..1d83293 100644
> --- a/target-arm/helper.h
> +++ b/target-arm/helper.h
> @@ -57,6 +57,7 @@ DEF_HELPER_1(cpsr_read, i32, env)
>  DEF_HELPER_3(v7m_msr, void, env, i32, i32)
>  DEF_HELPER_2(v7m_mrs, i32, env, i32)
>
> +DEF_HELPER_2(access_check_cp_reg, void, env, ptr)
>  DEF_HELPER_3(set_cp_reg, void, env, ptr, i32)
>  DEF_HELPER_2(get_cp_reg, i32, env, ptr)
>  DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64)
> diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
> index c812a9f..89b0978 100644
> --- a/target-arm/op_helper.c
> +++ b/target-arm/op_helper.c
> @@ -273,6 +273,24 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t 
> regno, uint32_t val)
>      }
>  }
>
> +void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip)
> +{
> +    const ARMCPRegInfo *ri = rip;
> +    switch (ri->accessfn(env, ri)) {
> +    case CP_ACCESS_OK:
> +        return;
> +    case CP_ACCESS_TRAP:
> +    case CP_ACCESS_TRAP_UNCATEGORIZED:
> +        /* These cases will eventually need to generate different
> +         * syndrome information.
> +         */
> +        break;
> +    default:
> +        g_assert_not_reached();
> +    }
> +    raise_exception(env, EXCP_UDEF);
> +}
> +
>  void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)
>  {
>      const ARMCPRegInfo *ri = rip;
> diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
> index a942609..d90ffd1 100644
> --- a/target-arm/translate-a64.c
> +++ b/target-arm/translate-a64.c
> @@ -1210,6 +1210,17 @@ static void handle_sys(DisasContext *s, uint32_t insn, 
> bool isread,
>          return;
>      }
>
> +    if (ri->accessfn) {
> +        /* Emit code to perform further access permissions checks at
> +         * runtime; this may result in an exception.
> +         */
> +        TCGv_ptr tmpptr;
> +        gen_a64_set_pc_im(s->pc - 4);
> +        tmpptr = tcg_const_ptr(ri);
> +        gen_helper_access_check_cp_reg(cpu_env, tmpptr);
> +        tcg_temp_free_ptr(tmpptr);
> +    }
> +
>      /* Handle special cases first */
>      switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
>      case ARM_CP_NOP:
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index 45886f9..2713081 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -6798,6 +6798,17 @@ static int disas_coproc_insn(CPUARMState * env, 
> DisasContext *s, uint32_t insn)
>              return 1;
>          }
>
> +        if (ri->accessfn) {
> +            /* Emit code to perform further access permissions checks at
> +             * runtime; this may result in an exception.
> +             */
> +            TCGv_ptr tmpptr;
> +            gen_set_pc_im(s, s->pc);
> +            tmpptr = tcg_const_ptr(ri);
> +            gen_helper_access_check_cp_reg(cpu_env, tmpptr);
> +            tcg_temp_free_ptr(tmpptr);
> +        }
> +
>          /* Handle special cases first */
>          switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
>          case ARM_CP_NOP:
> --
> 1.8.5
>
>



reply via email to

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