I have fixed the code to properly handle the CONTEXTIDR/FCSEIDR registers.
This is done in two parts:
1) I broke the FCSEIDR and CONTEXTIDR into separate secure/non-secure
definitions.
2) I updated the check that filters the secure duplicate instance caused by
registering unbanked register twice.










On 31 October 2014 14:01, Greg Bellows <greg.bell...@linaro.org> wrote:

>
>
> On 31 October 2014 07:44, Peter Maydell <peter.mayd...@linaro.org> wrote:
>
>> On 30 October 2014 21:28, Greg Bellows <greg.bell...@linaro.org> wrote:
>> > From: Fabian Aggeler <aggel...@ethz.ch>
>> >
>> > Prepare for cp register banking by inserting every cp register twice,
>> > once for secure world and once for non-secure world.
>> >
>> > Signed-off-by: Fabian Aggeler <aggel...@ethz.ch>
>> > Signed-off-by: Greg Bellows <greg.bell...@linaro.org>
>> >
>> > ---
>> >
>> > v7 -> v8
>> > - Updated define registers asserts to allow either a non-zero
>> fieldoffset or
>> >   non-zero bank_fieldoffsets.
>> > - Updated CP register hashing to always set the register fieldoffset
>> when
>> >   banked register offsets are specified.
>> >
>> > v5 -> v6
>> > - Fixed NS-bit number in the CPREG hash lookup from 27 to 29.
>> > - Switched to dedicated CPREG secure flags.
>> > - Fixed disablement of reset and migration of common 32/64-bit
>> registers.
>> > - Globally replace Aarch# with AArch#
>> >
>> > v4 -> v5
>> > - Added use of ARM CP secure/non-secure bank flags during register
>> processing
>> >   in define_one_arm_cp_reg_with_opaque().  We now only register the
>> specified
>> >   bank if only one flag is specified, otherwise we register both a
>> secure and
>> >   non-secure instance.
>> > ---
>> >  target-arm/helper.c | 98
>> ++++++++++++++++++++++++++++++++++++++++++++---------
>> >  1 file changed, 82 insertions(+), 16 deletions(-)
>> >
>> > diff --git a/target-arm/helper.c b/target-arm/helper.c
>> > index 959a46e..c1c6303 100644
>> > --- a/target-arm/helper.c
>> > +++ b/target-arm/helper.c
>> > @@ -3296,22 +3296,62 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu,
>> const ARMCPRegInfo *r,
>> >      uint32_t *key = g_new(uint32_t, 1);
>> >      ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo));
>> >      int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0;
>> > -    if (r->state == ARM_CP_STATE_BOTH && state == ARM_CP_STATE_AA32) {
>> > -        /* The AArch32 view of a shared register sees the lower 32 bits
>> > -         * of a 64 bit backing field. It is not migratable as the
>> AArch64
>> > -         * view handles that. AArch64 also handles reset.
>> > -         * We assume it is a cp15 register if the .cp field is left
>> unset.
>> > +
>> > +    if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) {
>> > +        /* Register is banked (using both entries in array).
>> > +         * Overwriting fieldoffset as the array is only used to define
>> > +         * banked registers but later only fieldoffset is used.
>> >           */
>> > -        if (r2->cp == 0) {
>> > -            r2->cp = 15;
>> > +        r2->fieldoffset = r->bank_fieldoffsets[nsbit];
>> > +    }
>> > +
>> > +    if (state == ARM_CP_STATE_AA32) {
>> > +        /* Clear the secure state flags and set based on incoming
>> nsbit */
>> > +        r2->secure &= ~(ARM_CP_SECSTATE_S | ARM_CP_SECSTATE_NS);
>> > +        r2->secure |= ARM_CP_SECSTATE_S << nsbit;
>>
>> This bitmanipulation looks like leftover from when these were in 'state';
>>    r2->secure = secstate;
>> should be sufficient (and you might as well put this down below the
>> 'r2->state = state' assignment, since it's harmless to do it for all
>> regdefs including 64 bit ones).
>>
>>
> It was in the previous code, but it is still necessary for marking whether
> the given register is secure or not.
>
>
>> > +
>> > +        if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) {
>> > +            /* If the register is banked and V8 is enabled then we
>> don't need
>> > +             * to migrate or reset the AArch32 version of the banked
>> > +             * registers as this will be handled through the AArch64
>> view.
>> > +             * If v7 then we don't need to migrate or reset the AArch32
>> > +             * non-secure bank as this will be handled through the
>> AArch64
>> > +             * view.  In this case the secure bank is not mirrored, so
>> we must
>> > +             * preserve it's reset criteria and allow it to be
>> migrated.
>> > +             *
>> > +             * The exception to the above is cpregs with a crn of 13
>> > +             * (specifically FCSEIDR and CONTEXTIDR) in which case
>> there may
>> > +             * not be an AArch64 equivalent for one or either bank so
>> migration
>> > +             * and reset must be preserved.
>> > +             */
>>
>> I'm not sure what this paragraph is trying to say. The AArch64 equivalent
>> of CONTEXTIDR(NS) is CONTEXTIDR_EL1. In v8 FCSEIDR is a constant RAZ/WI
>> register, so migration and reset aren't relevant anyway.
>>
>> In any case, if we only have a couple of special case registers where
>> this bank handling doesn't work, I suggest that we should handle them
>> by having two separate reginfo structs for the S and NS versions,
>> rather than special casing a specific crn value here.
>>
>
> It does not sound like the comment was clear.  The point of this code was
> to disable migration and reset of one or both banks.  If we know there is
> an aarch64 version (BOTH) then we know we can disable the ns bank
> instance.  If we are ARMv8 then we know that we can also disable the sec
> bank instance.  However, there was an exception in that neither CONTEXTIDR
> nor FCSEIDR actually have an ARMv8/AArch64 secure counterparts, so we still
> have to allow migration and reset even if ARMv8 is supported.
>
> You are correct that FCSEIDR is RAZ/WI in ARMv8, which is the exact issue
> as this is not the case in ARMv7.  I'll work through it to see if adding
> separate entries alleviates the need for the ugly conditional.  BTW, I
> didn't like this either, but at the time I hadn't found a more elegant
> approach.
>
>
>>
>> > +            if (r->state == ARM_CP_STATE_BOTH) {
>> > +                if ((arm_feature(&cpu->env, ARM_FEATURE_V8) && r->crn
>> != 13) ||
>> > +                    nsbit) {
>> > +                    r2->type |= ARM_CP_NO_MIGRATE;
>> > +                    r2->resetfn = arm_cp_reset_ignore;
>> > +                }
>> > +            }
>> > +        } else if (!nsbit) {
>> > +            /* The register is not banked so we only want to allow
>> migration of
>> > +             * the non-secure instance.
>> > +             */
>> > +            r2->type |= ARM_CP_NO_MIGRATE;
>> > +            r2->resetfn = arm_cp_reset_ignore;
>> >          }
>> > -        r2->type |= ARM_CP_NO_MIGRATE;
>> > -        r2->resetfn = arm_cp_reset_ignore;
>> > +
>> > +        if (r->state == ARM_CP_STATE_BOTH) {
>> > +            /* We assume it is a cp15 register if the .cp field is
>> left unset.
>> > +             */
>> > +            if (r2->cp == 0) {
>> > +                r2->cp = 15;
>> > +            }
>> > +
>> >  #ifdef HOST_WORDS_BIGENDIAN
>> > -        if (r2->fieldoffset) {
>> > -            r2->fieldoffset += sizeof(uint32_t);
>> > -        }
>> > +            if (r2->fieldoffset) {
>> > +                r2->fieldoffset += sizeof(uint32_t);
>> > +            }
>> >  #endif
>> > +        }
>> >      }
>> >      if (state == ARM_CP_STATE_AA64) {
>> >          /* To allow abbreviation of ARMCPRegInfo
>> > @@ -3460,10 +3500,14 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU
>> *cpu,
>> >       */
>> >      if (!(r->type & (ARM_CP_SPECIAL|ARM_CP_CONST))) {
>> >          if (r->access & PL3_R) {
>> > -            assert(r->fieldoffset || r->readfn);
>> > +            assert((r->fieldoffset ||
>> > +                   (r->bank_fieldoffsets[0] &&
>> r->bank_fieldoffsets[1])) ||
>> > +                   r->readfn);
>> >          }
>> >          if (r->access & PL3_W) {
>> > -            assert(r->fieldoffset || r->writefn);
>> > +            assert((r->fieldoffset ||
>> > +                   (r->bank_fieldoffsets[0] &&
>> r->bank_fieldoffsets[1])) ||
>> > +                   r->writefn);
>> >          }
>> >      }
>> >      /* Bad type field probably means missing sentinel at end of reg
>> list */
>> > @@ -3476,8 +3520,30 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU
>> *cpu,
>> >                      if (r->state != state && r->state !=
>> ARM_CP_STATE_BOTH) {
>> >                          continue;
>> >                      }
>> > -                    add_cpreg_to_hashtable(cpu, r, opaque, state,
>> > -                                           crm, opc1, opc2, SCR_NS);
>> > +                    if (state == ARM_CP_STATE_AA32) {
>> > +                        /* Under AArch32 CP registers can be common
>> > +                         * (same for secure and non-secure world) or
>> banked.
>> > +                         */
>> > +                        uint32_t s =
>> > +                          r->secure & (ARM_CP_SECSTATE_S |
>> ARM_CP_SECSTATE_NS);
>> > +                        if (ARM_CP_SECSTATE_S == s) {
>>
>> As a general remark, don't use this sort of "yoda conditional" with the
>> constant on the LHS of the ==, please.
>>
>
> Fixed in v9.
>
>
>>
>> > +                            add_cpreg_to_hashtable(cpu, r, opaque,
>> state,
>> > +                                    crm, opc1, opc2, !SCR_NS);
>> > +                        } else if (ARM_CP_SECSTATE_NS == s) {
>> > +                            add_cpreg_to_hashtable(cpu, r, opaque,
>> state,
>> > +                                    crm, opc1, opc2, SCR_NS);
>> > +                        } else {
>> > +                            add_cpreg_to_hashtable(cpu, r, opaque,
>> state,
>> > +                                    crm, opc1, opc2, !SCR_NS);
>> > +                            add_cpreg_to_hashtable(cpu, r, opaque,
>> state,
>> > +                                    crm, opc1, opc2, SCR_NS);
>> > +                        }
>>
>> Given the change to make add_cpreg_to_hashtable() take an ARM_CP_SECSTATE*
>> constant that I suggested in the previous patch, you can simplify this to
>>
>>     switch (r->secure) {
>>         case ARM_CP_SECSTATE_S:
>>         case ARM_CP_SECSTATE_NS:
>>             add_cpreg_to_hashtable(cpu, r, opaque, state, r->secure,
>> crm, opc1, opc2);
>>             break;
>>         default:
>>             add_cpreg_to_hashtable(cpu, r, opaque, state,
>> ARM_CP_SECSTATE_S, crm, opc1, opc2);
>>             add_cpreg_to_hashtable(cpu, r, opaque, state,
>> ARM_CP_SECSTATE_NS, crm, opc1, opc2);
>>             break;
>>     }
>>
>
>> > +                    } else {
>> > +                        /* AArch64 registers get mapped to non-secure
>> instance
>> > +                         * of AArch32 */
>> > +                        add_cpreg_to_hashtable(cpu, r, opaque, state,
>> > +                                crm, opc1, opc2, SCR_NS);
>> > +                    }
>> >                  }
>> >              }
>> >          }
>> > --
>> > 1.8.3.2
>>
>> thanks
>> -- PMM
>>
>
>

Reply via email to