diff mbox

[v4,14/21] target-arm: Implement AArch64 views of fault status and data registers

Message ID 1394134385-1727-15-git-send-email-peter.maydell@linaro.org
State Superseded
Headers show

Commit Message

Peter Maydell March 6, 2014, 7:32 p.m. UTC
From: Rob Herring <rob.herring@linaro.org>

Implement AArch64 views of ESR_EL1 and FAR_EL1, and make the 32 bit
DFSR, DFAR, IFAR share state with them as architecturally specified.
The IFSR doesn't share state with any AArch64 register visible at EL1,
so just rename the state field without widening it to 64 bits.

Signed-off-by: Rob Herring <rob.herring@linaro.org>
[PMM: Minor tweaks; fix some bugs involving inconsistencies between
 use of offsetof() or offsetoflow32() and struct field width]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu.c    |  2 +-
 target-arm/cpu.h    |  7 +++----
 target-arm/helper.c | 38 +++++++++++++++++++++++++-------------
 3 files changed, 29 insertions(+), 18 deletions(-)

Comments

Peter Crosthwaite March 17, 2014, 5:30 a.m. UTC | #1
On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> From: Rob Herring <rob.herring@linaro.org>
>
> Implement AArch64 views of ESR_EL1 and FAR_EL1, and make the 32 bit
> DFSR, DFAR, IFAR share state with them as architecturally specified.
> The IFSR doesn't share state with any AArch64 register visible at EL1,
> so just rename the state field without widening it to 64 bits.
>
> Signed-off-by: Rob Herring <rob.herring@linaro.org>
> [PMM: Minor tweaks; fix some bugs involving inconsistencies between
>  use of offsetof() or offsetoflow32() and struct field width]
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target-arm/cpu.c    |  2 +-
>  target-arm/cpu.h    |  7 +++----
>  target-arm/helper.c | 38 +++++++++++++++++++++++++-------------
>  3 files changed, 29 insertions(+), 18 deletions(-)
>
> diff --git a/target-arm/cpu.c b/target-arm/cpu.c
> index 871ed09..948fd44 100644
> --- a/target-arm/cpu.c
> +++ b/target-arm/cpu.c
> @@ -419,7 +419,7 @@ static void arm1026_initfn(Object *obj)
>          ARMCPRegInfo ifar = {
>              .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1,
>              .access = PL1_RW,
> -            .fieldoffset = offsetof(CPUARMState, cp15.c6_insn),
> +            .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
>              .resetvalue = 0
>          };
>          define_one_arm_cp_reg(cpu, &ifar);
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index ffa4b37..e51add2 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -181,11 +181,10 @@ typedef struct CPUARMState {
>                          MPU write buffer control.  */
>          uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
>          uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
> -        uint32_t c5_insn; /* Fault status registers.  */
> -        uint32_t c5_data;
> +        uint32_t ifsr_el2; /* Fault status registers.  */
> +        uint64_t esr_el1;
>          uint32_t c6_region[8]; /* MPU base/size registers.  */
> -        uint32_t c6_insn; /* Fault address registers.  */
> -        uint32_t c6_data;
> +        uint64_t far_el1; /* Fault address registers.  */
>          uint32_t c7_par;  /* Translation result. */
>          uint32_t c7_par_hi;  /* Translation result, high 32 bits */
>          uint32_t c9_insn; /* Cache lockdown registers.  */
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index cbef0e5..8d96b5c 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -456,7 +456,8 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
>      { .name = "DMB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 5,
>        .access = PL0_W, .type = ARM_CP_NOP },
>      { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2,
> -      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c6_insn),
> +      .access = PL1_RW,
> +      .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
>        .resetvalue = 0, },
>      /* Watchpoint Fault Address Register : should actually only be present
>       * for 1136, 1176, 11MPCore.
> @@ -1316,11 +1317,16 @@ static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
>
>  static const ARMCPRegInfo vmsa_cp_reginfo[] = {
>      { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
> -      .access = PL1_RW,
> -      .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, },
> +      .access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
> +      .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1),
> +      .resetfn = arm_cp_reset_ignore, },
>      { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
>        .access = PL1_RW,
> -      .fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0, },
> +      .fieldoffset = offsetof(CPUARMState, cp15.ifsr_el2), .resetvalue = 0, },
> +    { .name = "ESR_EL1", .state = ARM_CP_STATE_AA64,
> +      .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0,
> +      .access = PL1_RW,
> +      .fieldoffset = offsetof(CPUARMState, cp15.esr_el1), .resetvalue = 0, },
>      { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH,
>        .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
>        .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1),
> @@ -1338,8 +1344,10 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
>        .access = PL1_RW, .type = ARM_CP_NO_MIGRATE, .writefn = vmsa_ttbcr_write,
>        .resetfn = arm_cp_reset_ignore, .raw_writefn = vmsa_ttbcr_raw_write,
>        .fieldoffset = offsetoflow32(CPUARMState, cp15.c2_control) },
> -    { .name = "DFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
> -      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c6_data),
> +    /* 64-bit FAR; this entry also gives us the AArch32 DFAR */
> +    { .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
> +      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el1),
>        .resetvalue = 0, },
>      REGINFO_SENTINEL
>  };
> @@ -1379,7 +1387,8 @@ static void omap_cachemaint_write(CPUARMState *env, const ARMCPRegInfo *ri,
>  static const ARMCPRegInfo omap_cp_reginfo[] = {
>      { .name = "DFSR", .cp = 15, .crn = 5, .crm = CP_ANY,
>        .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_OVERRIDE,
> -      .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, },
> +      .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1),
> +      .resetvalue = 0, },
>      { .name = "", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0,
>        .access = PL1_RW, .type = ARM_CP_NOP },
>      { .name = "TICONFIG", .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0,
> @@ -2979,20 +2988,23 @@ void arm_cpu_do_interrupt(CPUState *cs)
>          env->exception.fsr = 2;
>          /* Fall through to prefetch abort.  */
>      case EXCP_PREFETCH_ABORT:
> -        env->cp15.c5_insn = env->exception.fsr;
> -        env->cp15.c6_insn = env->exception.vaddress;
> +        env->cp15.ifsr_el2 = env->exception.fsr;
> +        env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
> +                                      env->exception.vaddress);

Is it better to just grab the CPRegInfo and pass it to raw_write() to
do the deposit dirty work?

Regards,
Peter

>          qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
> -                      env->cp15.c5_insn, env->cp15.c6_insn);
> +                      env->cp15.ifsr_el2, (uint32_t)env->exception.vaddress);
>          new_mode = ARM_CPU_MODE_ABT;
>          addr = 0x0c;
>          mask = CPSR_A | CPSR_I;
>          offset = 4;
>          break;
>      case EXCP_DATA_ABORT:
> -        env->cp15.c5_data = env->exception.fsr;
> -        env->cp15.c6_data = env->exception.vaddress;
> +        env->cp15.esr_el1 = env->exception.fsr;
> +        env->cp15.far_el1 = deposit64(env->cp15.far_el1, 0, 32,
> +                                      env->exception.vaddress);
>          qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
> -                      env->cp15.c5_data, env->cp15.c6_data);
> +                      (uint32_t)env->cp15.esr_el1,
> +                      (uint32_t)env->exception.vaddress);
>          new_mode = ARM_CPU_MODE_ABT;
>          addr = 0x10;
>          mask = CPSR_A | CPSR_I;
> --
> 1.9.0
>
>
Peter Maydell March 17, 2014, 1:06 p.m. UTC | #2
On 17 March 2014 05:30, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> @@ -2979,20 +2988,23 @@ void arm_cpu_do_interrupt(CPUState *cs)
>>          env->exception.fsr = 2;
>>          /* Fall through to prefetch abort.  */
>>      case EXCP_PREFETCH_ABORT:
>> -        env->cp15.c5_insn = env->exception.fsr;
>> -        env->cp15.c6_insn = env->exception.vaddress;
>> +        env->cp15.ifsr_el2 = env->exception.fsr;
>> +        env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
>> +                                      env->exception.vaddress);
>
> Is it better to just grab the CPRegInfo and pass it to raw_write() to
> do the deposit dirty work?

You'd have to do a hash-table lookup and it would be an odd
case compared to the other registers we update here, so I think
just directly depositing to the state field is simpler.

thanks
-- PMM
Peter Crosthwaite March 17, 2014, 1:17 p.m. UTC | #3
On Mon, Mar 17, 2014 at 11:06 PM, Peter Maydell
<peter.maydell@linaro.org> wrote:
> On 17 March 2014 05:30, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
>> On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>>> @@ -2979,20 +2988,23 @@ void arm_cpu_do_interrupt(CPUState *cs)
>>>          env->exception.fsr = 2;
>>>          /* Fall through to prefetch abort.  */
>>>      case EXCP_PREFETCH_ABORT:
>>> -        env->cp15.c5_insn = env->exception.fsr;
>>> -        env->cp15.c6_insn = env->exception.vaddress;
>>> +        env->cp15.ifsr_el2 = env->exception.fsr;
>>> +        env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
>>> +                                      env->exception.vaddress);
>>
>> Is it better to just grab the CPRegInfo and pass it to raw_write() to
>> do the deposit dirty work?
>
> You'd have to do a hash-table lookup and it would be an odd
> case compared to the other registers we update here, so I think
> just directly depositing to the state field is simpler.
>

OK fair enough. I was thinking just pass the & of static const
CPRegInfo (if its even visible here) rather than doing a lookup. But
then I spose you have a preformatted CPRegInfo that may or may not be
correct.

FWIW I know you dislike unions, but it would solve this one. In
general its verbose and cumbersome, but I think its applicable to the
ones where you have wierd register sharing policys (like the somewhat
numerically unrealted IFAR and DFAR being high and low words of FAR).

Regards,
Peter

> thanks
> -- PMM
>
diff mbox

Patch

diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 871ed09..948fd44 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -419,7 +419,7 @@  static void arm1026_initfn(Object *obj)
         ARMCPRegInfo ifar = {
             .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1,
             .access = PL1_RW,
-            .fieldoffset = offsetof(CPUARMState, cp15.c6_insn),
+            .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
             .resetvalue = 0
         };
         define_one_arm_cp_reg(cpu, &ifar);
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index ffa4b37..e51add2 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -181,11 +181,10 @@  typedef struct CPUARMState {
                         MPU write buffer control.  */
         uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
         uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
-        uint32_t c5_insn; /* Fault status registers.  */
-        uint32_t c5_data;
+        uint32_t ifsr_el2; /* Fault status registers.  */
+        uint64_t esr_el1;
         uint32_t c6_region[8]; /* MPU base/size registers.  */
-        uint32_t c6_insn; /* Fault address registers.  */
-        uint32_t c6_data;
+        uint64_t far_el1; /* Fault address registers.  */
         uint32_t c7_par;  /* Translation result. */
         uint32_t c7_par_hi;  /* Translation result, high 32 bits */
         uint32_t c9_insn; /* Cache lockdown registers.  */
diff --git a/target-arm/helper.c b/target-arm/helper.c
index cbef0e5..8d96b5c 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -456,7 +456,8 @@  static const ARMCPRegInfo v6_cp_reginfo[] = {
     { .name = "DMB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 5,
       .access = PL0_W, .type = ARM_CP_NOP },
     { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2,
-      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c6_insn),
+      .access = PL1_RW,
+      .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
       .resetvalue = 0, },
     /* Watchpoint Fault Address Register : should actually only be present
      * for 1136, 1176, 11MPCore.
@@ -1316,11 +1317,16 @@  static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
 
 static const ARMCPRegInfo vmsa_cp_reginfo[] = {
     { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
-      .access = PL1_RW,
-      .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, },
+      .access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
+      .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1),
+      .resetfn = arm_cp_reset_ignore, },
     { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
       .access = PL1_RW,
-      .fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0, },
+      .fieldoffset = offsetof(CPUARMState, cp15.ifsr_el2), .resetvalue = 0, },
+    { .name = "ESR_EL1", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0,
+      .access = PL1_RW,
+      .fieldoffset = offsetof(CPUARMState, cp15.esr_el1), .resetvalue = 0, },
     { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1),
@@ -1338,8 +1344,10 @@  static const ARMCPRegInfo vmsa_cp_reginfo[] = {
       .access = PL1_RW, .type = ARM_CP_NO_MIGRATE, .writefn = vmsa_ttbcr_write,
       .resetfn = arm_cp_reset_ignore, .raw_writefn = vmsa_ttbcr_raw_write,
       .fieldoffset = offsetoflow32(CPUARMState, cp15.c2_control) },
-    { .name = "DFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
-      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c6_data),
+    /* 64-bit FAR; this entry also gives us the AArch32 DFAR */
+    { .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
+      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el1),
       .resetvalue = 0, },
     REGINFO_SENTINEL
 };
@@ -1379,7 +1387,8 @@  static void omap_cachemaint_write(CPUARMState *env, const ARMCPRegInfo *ri,
 static const ARMCPRegInfo omap_cp_reginfo[] = {
     { .name = "DFSR", .cp = 15, .crn = 5, .crm = CP_ANY,
       .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_OVERRIDE,
-      .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, },
+      .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1),
+      .resetvalue = 0, },
     { .name = "", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .type = ARM_CP_NOP },
     { .name = "TICONFIG", .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0,
@@ -2979,20 +2988,23 @@  void arm_cpu_do_interrupt(CPUState *cs)
         env->exception.fsr = 2;
         /* Fall through to prefetch abort.  */
     case EXCP_PREFETCH_ABORT:
-        env->cp15.c5_insn = env->exception.fsr;
-        env->cp15.c6_insn = env->exception.vaddress;
+        env->cp15.ifsr_el2 = env->exception.fsr;
+        env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
+                                      env->exception.vaddress);
         qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
-                      env->cp15.c5_insn, env->cp15.c6_insn);
+                      env->cp15.ifsr_el2, (uint32_t)env->exception.vaddress);
         new_mode = ARM_CPU_MODE_ABT;
         addr = 0x0c;
         mask = CPSR_A | CPSR_I;
         offset = 4;
         break;
     case EXCP_DATA_ABORT:
-        env->cp15.c5_data = env->exception.fsr;
-        env->cp15.c6_data = env->exception.vaddress;
+        env->cp15.esr_el1 = env->exception.fsr;
+        env->cp15.far_el1 = deposit64(env->cp15.far_el1, 0, 32,
+                                      env->exception.vaddress);
         qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
-                      env->cp15.c5_data, env->cp15.c6_data);
+                      (uint32_t)env->cp15.esr_el1,
+                      (uint32_t)env->exception.vaddress);
         new_mode = ARM_CPU_MODE_ABT;
         addr = 0x10;
         mask = CPSR_A | CPSR_I;