diff mbox

[5/6] target-arm: Implement MDCR_EL2.TDA and MDCR_EL2.TDA traps

Message ID 1454690704-16233-6-git-send-email-peter.maydell@linaro.org
State New
Headers show

Commit Message

Peter Maydell Feb. 5, 2016, 4:45 p.m. UTC
Implement the debug register traps controlled by MDCR_EL2.TDA
and MDCR_EL3.TDA.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/helper.c | 39 ++++++++++++++++++++++++++++++---------
 1 file changed, 30 insertions(+), 9 deletions(-)

Comments

Sergey Fedorov Feb. 8, 2016, 4:31 p.m. UTC | #1
One of the MDCR_EL2's should be MDCR_EL3 instead.

On 05.02.2016 19:45, Peter Maydell wrote:
> Implement the debug register traps controlled by MDCR_EL2.TDA
> and MDCR_EL3.TDA.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target-arm/helper.c | 39 ++++++++++++++++++++++++++++++---------
>  1 file changed, 30 insertions(+), 9 deletions(-)
>
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 8c2adbc..064b415 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -420,6 +420,24 @@ static CPAccessResult access_tdra(CPUARMState *env, const ARMCPRegInfo *ri,
>      return CP_ACCESS_OK;
>  }
>  
> +/* Check for traps to general debug registers, which are controlled
> + * by MDCR_EL2.TDA for EL2 and MDCR_EL3.TDA for EL3.
> + */
> +static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri,
> +                                  bool isread)
> +{
> +    int el = arm_current_el(env);
> +
> +    if (el < 2 && (env->cp15.mdcr_el2 & MDCR_TDA)
> +        && !arm_is_secure_below_el3(env)) {
> +        return CP_ACCESS_TRAP_EL2;
> +    }
> +    if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDA)) {
> +        return CP_ACCESS_TRAP_EL3;
> +    }
> +    return CP_ACCESS_OK;
> +}
> +
>  static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
>  {
>      ARMCPU *cpu = arm_env_get_cpu(env);
> @@ -3385,7 +3403,8 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
>        .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
>      { .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH,
>        .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1,
> -      .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
> +      .access = PL2_RW, .accessfn = access_tda,
> +      .type = ARM_CP_CONST, .resetvalue = 0 },
>      { .name = "HPFAR_EL2", .state = ARM_CP_STATE_BOTH,
>        .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4,
>        .access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any,
> @@ -3804,7 +3823,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
>      /* Monitor debug system control register; the 32-bit alias is DBGDSCRext. */
>      { .name = "MDSCR_EL1", .state = ARM_CP_STATE_BOTH,
>        .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2,
> -      .access = PL1_RW,
> +      .access = PL1_RW, .accessfn = access_tda,
>        .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1),
>        .resetvalue = 0 },
>      /* MDCCSR_EL0, aka DBGDSCRint. This is a read-only mirror of MDSCR_EL1.
> @@ -3813,7 +3832,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
>      { .name = "MDCCSR_EL0", .state = ARM_CP_STATE_BOTH,
>        .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0,
>        .type = ARM_CP_ALIAS,
> -      .access = PL1_R,
> +      .access = PL1_R, .accessfn = access_tda,

From ARMv8 ARM rev. A.h: "If MDSCR_EL1.TDCC==1, EL0 read accesses to
this register are trapped to EL1." But it seems like we just don't
implement "Config-RO for EL0" so far. Maybe it's worth to implement a
separate function for checks controlled by MDSCR_EL1.TDCC?

>        .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), },
>      { .name = "OSLAR_EL1", .state = ARM_CP_STATE_BOTH,
>        .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 4,
> @@ -3835,7 +3854,8 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
>       */
>      { .name = "DBGVCR",
>        .cp = 14, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0,
> -      .access = PL1_RW, .type = ARM_CP_NOP },
> +      .access = PL1_RW, .accessfn = access_tda,
> +      .type = ARM_CP_NOP },
>      REGINFO_SENTINEL
>  };
>  
> @@ -4100,7 +4120,8 @@ static void define_debug_regs(ARMCPU *cpu)
>      int wrps, brps, ctx_cmps;
>      ARMCPRegInfo dbgdidr = {
>          .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0,
> -        .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = cpu->dbgdidr,
> +        .access = PL0_R, .accessfn = access_tda,
> +        .type = ARM_CP_CONST, .resetvalue = cpu->dbgdidr,

The same concern as above.

Kind regards,
Sergey

>      };
>  
>      /* Note that all these register fields hold "number of Xs minus 1". */
> @@ -4131,13 +4152,13 @@ static void define_debug_regs(ARMCPU *cpu)
>          ARMCPRegInfo dbgregs[] = {
>              { .name = "DBGBVR", .state = ARM_CP_STATE_BOTH,
>                .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4,
> -              .access = PL1_RW,
> +              .access = PL1_RW, .accessfn = access_tda,
>                .fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]),
>                .writefn = dbgbvr_write, .raw_writefn = raw_write
>              },
>              { .name = "DBGBCR", .state = ARM_CP_STATE_BOTH,
>                .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 5,
> -              .access = PL1_RW,
> +              .access = PL1_RW, .accessfn = access_tda,
>                .fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]),
>                .writefn = dbgbcr_write, .raw_writefn = raw_write
>              },
> @@ -4150,13 +4171,13 @@ static void define_debug_regs(ARMCPU *cpu)
>          ARMCPRegInfo dbgregs[] = {
>              { .name = "DBGWVR", .state = ARM_CP_STATE_BOTH,
>                .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6,
> -              .access = PL1_RW,
> +              .access = PL1_RW, .accessfn = access_tda,
>                .fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]),
>                .writefn = dbgwvr_write, .raw_writefn = raw_write
>              },
>              { .name = "DBGWCR", .state = ARM_CP_STATE_BOTH,
>                .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 7,
> -              .access = PL1_RW,
> +              .access = PL1_RW, .accessfn = access_tda,
>                .fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]),
>                .writefn = dbgwcr_write, .raw_writefn = raw_write
>              },
Peter Maydell Feb. 8, 2016, 4:38 p.m. UTC | #2
On 8 February 2016 at 16:31, Sergey Fedorov <serge.fdrv@gmail.com> wrote:
> One of the MDCR_EL2's should be MDCR_EL3 instead.

Oops, yes :-)

> On 05.02.2016 19:45, Peter Maydell wrote:
>> Implement the debug register traps controlled by MDCR_EL2.TDA
>> and MDCR_EL3.TDA.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  target-arm/helper.c | 39 ++++++++++++++++++++++++++++++---------
>>  1 file changed, 30 insertions(+), 9 deletions(-)
>>
>> diff --git a/target-arm/helper.c b/target-arm/helper.c
>> index 8c2adbc..064b415 100644
>> --- a/target-arm/helper.c
>> +++ b/target-arm/helper.c
>> @@ -420,6 +420,24 @@ static CPAccessResult access_tdra(CPUARMState *env, const ARMCPRegInfo *ri,
>>      return CP_ACCESS_OK;
>>  }
>>
>> +/* Check for traps to general debug registers, which are controlled
>> + * by MDCR_EL2.TDA for EL2 and MDCR_EL3.TDA for EL3.
>> + */
>> +static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri,
>> +                                  bool isread)
>> +{
>> +    int el = arm_current_el(env);
>> +
>> +    if (el < 2 && (env->cp15.mdcr_el2 & MDCR_TDA)
>> +        && !arm_is_secure_below_el3(env)) {
>> +        return CP_ACCESS_TRAP_EL2;
>> +    }
>> +    if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDA)) {
>> +        return CP_ACCESS_TRAP_EL3;
>> +    }
>> +    return CP_ACCESS_OK;
>> +}
>> +
>>  static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
>>  {
>>      ARMCPU *cpu = arm_env_get_cpu(env);
>> @@ -3385,7 +3403,8 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
>>        .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
>>      { .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH,
>>        .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1,
>> -      .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
>> +      .access = PL2_RW, .accessfn = access_tda,
>> +      .type = ARM_CP_CONST, .resetvalue = 0 },
>>      { .name = "HPFAR_EL2", .state = ARM_CP_STATE_BOTH,
>>        .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4,
>>        .access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any,
>> @@ -3804,7 +3823,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
>>      /* Monitor debug system control register; the 32-bit alias is DBGDSCRext. */
>>      { .name = "MDSCR_EL1", .state = ARM_CP_STATE_BOTH,
>>        .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2,
>> -      .access = PL1_RW,
>> +      .access = PL1_RW, .accessfn = access_tda,
>>        .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1),
>>        .resetvalue = 0 },
>>      /* MDCCSR_EL0, aka DBGDSCRint. This is a read-only mirror of MDSCR_EL1.
>> @@ -3813,7 +3832,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
>>      { .name = "MDCCSR_EL0", .state = ARM_CP_STATE_BOTH,
>>        .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0,
>>        .type = ARM_CP_ALIAS,
>> -      .access = PL1_R,
>> +      .access = PL1_R, .accessfn = access_tda,
>
> From ARMv8 ARM rev. A.h: "If MDSCR_EL1.TDCC==1, EL0 read accesses to
> this register are trapped to EL1." But it seems like we just don't
> implement "Config-RO for EL0" so far.

Yes. There's a comment about this, though it's just outside the
context region that diff has produced.

> Maybe it's worth to implement a
> separate function for checks controlled by MDSCR_EL1.TDCC?

I think that's a separate issue from the EL2/EL3 traps and
should go in its own patch. This series is just trying to get
EL3 right.

thanks
-- PMM
Sergey Fedorov Feb. 8, 2016, 4:44 p.m. UTC | #3
On 08.02.2016 19:38, Peter Maydell wrote:
> On 8 February 2016 at 16:31, Sergey Fedorov <serge.fdrv@gmail.com> wrote:
>> One of the MDCR_EL2's should be MDCR_EL3 instead.
> Oops, yes :-)
>
>> On 05.02.2016 19:45, Peter Maydell wrote:
>>> Implement the debug register traps controlled by MDCR_EL2.TDA
>>> and MDCR_EL3.TDA.
>>>
>>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>>> ---
>>>  target-arm/helper.c | 39 ++++++++++++++++++++++++++++++---------
>>>  1 file changed, 30 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/target-arm/helper.c b/target-arm/helper.c
>>> index 8c2adbc..064b415 100644
>>> --- a/target-arm/helper.c
>>> +++ b/target-arm/helper.c
>>> @@ -420,6 +420,24 @@ static CPAccessResult access_tdra(CPUARMState *env, const ARMCPRegInfo *ri,
>>>      return CP_ACCESS_OK;
>>>  }
>>>
>>> +/* Check for traps to general debug registers, which are controlled
>>> + * by MDCR_EL2.TDA for EL2 and MDCR_EL3.TDA for EL3.
>>> + */
>>> +static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri,
>>> +                                  bool isread)
>>> +{
>>> +    int el = arm_current_el(env);
>>> +
>>> +    if (el < 2 && (env->cp15.mdcr_el2 & MDCR_TDA)
>>> +        && !arm_is_secure_below_el3(env)) {
>>> +        return CP_ACCESS_TRAP_EL2;
>>> +    }
>>> +    if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDA)) {
>>> +        return CP_ACCESS_TRAP_EL3;
>>> +    }
>>> +    return CP_ACCESS_OK;
>>> +}
>>> +
>>>  static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
>>>  {
>>>      ARMCPU *cpu = arm_env_get_cpu(env);
>>> @@ -3385,7 +3403,8 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
>>>        .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
>>>      { .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH,
>>>        .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1,
>>> -      .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
>>> +      .access = PL2_RW, .accessfn = access_tda,
>>> +      .type = ARM_CP_CONST, .resetvalue = 0 },
>>>      { .name = "HPFAR_EL2", .state = ARM_CP_STATE_BOTH,
>>>        .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4,
>>>        .access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any,
>>> @@ -3804,7 +3823,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
>>>      /* Monitor debug system control register; the 32-bit alias is DBGDSCRext. */
>>>      { .name = "MDSCR_EL1", .state = ARM_CP_STATE_BOTH,
>>>        .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2,
>>> -      .access = PL1_RW,
>>> +      .access = PL1_RW, .accessfn = access_tda,
>>>        .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1),
>>>        .resetvalue = 0 },
>>>      /* MDCCSR_EL0, aka DBGDSCRint. This is a read-only mirror of MDSCR_EL1.
>>> @@ -3813,7 +3832,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
>>>      { .name = "MDCCSR_EL0", .state = ARM_CP_STATE_BOTH,
>>>        .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0,
>>>        .type = ARM_CP_ALIAS,
>>> -      .access = PL1_R,
>>> +      .access = PL1_R, .accessfn = access_tda,
>> From ARMv8 ARM rev. A.h: "If MDSCR_EL1.TDCC==1, EL0 read accesses to
>> this register are trapped to EL1." But it seems like we just don't
>> implement "Config-RO for EL0" so far.
> Yes. There's a comment about this, though it's just outside the
> context region that diff has produced.
>
>> Maybe it's worth to implement a
>> separate function for checks controlled by MDSCR_EL1.TDCC?
> I think that's a separate issue from the EL2/EL3 traps and
> should go in its own patch. This series is just trying to get
> EL3 right.

Okay, with fixed subject:

Reviewed-by: Sergey Fedorov <serge.fdrv@gmail.com>

Kind regards,
Sergey
diff mbox

Patch

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 8c2adbc..064b415 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -420,6 +420,24 @@  static CPAccessResult access_tdra(CPUARMState *env, const ARMCPRegInfo *ri,
     return CP_ACCESS_OK;
 }
 
+/* Check for traps to general debug registers, which are controlled
+ * by MDCR_EL2.TDA for EL2 and MDCR_EL3.TDA for EL3.
+ */
+static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri,
+                                  bool isread)
+{
+    int el = arm_current_el(env);
+
+    if (el < 2 && (env->cp15.mdcr_el2 & MDCR_TDA)
+        && !arm_is_secure_below_el3(env)) {
+        return CP_ACCESS_TRAP_EL2;
+    }
+    if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDA)) {
+        return CP_ACCESS_TRAP_EL3;
+    }
+    return CP_ACCESS_OK;
+}
+
 static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
     ARMCPU *cpu = arm_env_get_cpu(env);
@@ -3385,7 +3403,8 @@  static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
       .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
     { .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1,
-      .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
+      .access = PL2_RW, .accessfn = access_tda,
+      .type = ARM_CP_CONST, .resetvalue = 0 },
     { .name = "HPFAR_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4,
       .access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any,
@@ -3804,7 +3823,7 @@  static const ARMCPRegInfo debug_cp_reginfo[] = {
     /* Monitor debug system control register; the 32-bit alias is DBGDSCRext. */
     { .name = "MDSCR_EL1", .state = ARM_CP_STATE_BOTH,
       .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2,
-      .access = PL1_RW,
+      .access = PL1_RW, .accessfn = access_tda,
       .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1),
       .resetvalue = 0 },
     /* MDCCSR_EL0, aka DBGDSCRint. This is a read-only mirror of MDSCR_EL1.
@@ -3813,7 +3832,7 @@  static const ARMCPRegInfo debug_cp_reginfo[] = {
     { .name = "MDCCSR_EL0", .state = ARM_CP_STATE_BOTH,
       .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0,
       .type = ARM_CP_ALIAS,
-      .access = PL1_R,
+      .access = PL1_R, .accessfn = access_tda,
       .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), },
     { .name = "OSLAR_EL1", .state = ARM_CP_STATE_BOTH,
       .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 4,
@@ -3835,7 +3854,8 @@  static const ARMCPRegInfo debug_cp_reginfo[] = {
      */
     { .name = "DBGVCR",
       .cp = 14, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0,
-      .access = PL1_RW, .type = ARM_CP_NOP },
+      .access = PL1_RW, .accessfn = access_tda,
+      .type = ARM_CP_NOP },
     REGINFO_SENTINEL
 };
 
@@ -4100,7 +4120,8 @@  static void define_debug_regs(ARMCPU *cpu)
     int wrps, brps, ctx_cmps;
     ARMCPRegInfo dbgdidr = {
         .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0,
-        .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = cpu->dbgdidr,
+        .access = PL0_R, .accessfn = access_tda,
+        .type = ARM_CP_CONST, .resetvalue = cpu->dbgdidr,
     };
 
     /* Note that all these register fields hold "number of Xs minus 1". */
@@ -4131,13 +4152,13 @@  static void define_debug_regs(ARMCPU *cpu)
         ARMCPRegInfo dbgregs[] = {
             { .name = "DBGBVR", .state = ARM_CP_STATE_BOTH,
               .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4,
-              .access = PL1_RW,
+              .access = PL1_RW, .accessfn = access_tda,
               .fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]),
               .writefn = dbgbvr_write, .raw_writefn = raw_write
             },
             { .name = "DBGBCR", .state = ARM_CP_STATE_BOTH,
               .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 5,
-              .access = PL1_RW,
+              .access = PL1_RW, .accessfn = access_tda,
               .fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]),
               .writefn = dbgbcr_write, .raw_writefn = raw_write
             },
@@ -4150,13 +4171,13 @@  static void define_debug_regs(ARMCPU *cpu)
         ARMCPRegInfo dbgregs[] = {
             { .name = "DBGWVR", .state = ARM_CP_STATE_BOTH,
               .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6,
-              .access = PL1_RW,
+              .access = PL1_RW, .accessfn = access_tda,
               .fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]),
               .writefn = dbgwvr_write, .raw_writefn = raw_write
             },
             { .name = "DBGWCR", .state = ARM_CP_STATE_BOTH,
               .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 7,
-              .access = PL1_RW,
+              .access = PL1_RW, .accessfn = access_tda,
               .fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]),
               .writefn = dbgwcr_write, .raw_writefn = raw_write
             },