diff mbox series

[14/16] target/arm: Implement ESB instruction

Message ID 20220409000742.293691-15-richard.henderson@linaro.org
State New
Headers show
Series target/arm: Implement features Debugv8p4, RAS, IESB | expand

Commit Message

Richard Henderson April 9, 2022, 12:07 a.m. UTC
Check for and defer any pending virtual SError.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.h        |  1 +
 target/arm/a32.decode      | 16 +++++++++-----
 target/arm/t32.decode      | 18 +++++++--------
 target/arm/op_helper.c     | 45 ++++++++++++++++++++++++++++++++++++++
 target/arm/translate-a64.c |  7 ++++++
 target/arm/translate.c     | 10 +++++++++
 6 files changed, 82 insertions(+), 15 deletions(-)

Comments

Peter Maydell April 11, 2022, 4:18 p.m. UTC | #1
On Sat, 9 Apr 2022 at 01:18, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Check for and defer any pending virtual SError.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/arm/helper.h        |  1 +
>  target/arm/a32.decode      | 16 +++++++++-----
>  target/arm/t32.decode      | 18 +++++++--------
>  target/arm/op_helper.c     | 45 ++++++++++++++++++++++++++++++++++++++
>  target/arm/translate-a64.c |  7 ++++++
>  target/arm/translate.c     | 10 +++++++++
>  6 files changed, 82 insertions(+), 15 deletions(-)
>
> diff --git a/target/arm/helper.h b/target/arm/helper.h
> index b463d9343b..bb7f901668 100644
> --- a/target/arm/helper.h
> +++ b/target/arm/helper.h
> @@ -54,6 +54,7 @@ DEF_HELPER_1(wfe, void, env)
>  DEF_HELPER_1(yield, void, env)
>  DEF_HELPER_1(pre_hvc, void, env)
>  DEF_HELPER_2(pre_smc, void, env, i32)
> +DEF_HELPER_1(esb, void, env)
>
>  DEF_HELPER_3(cpsr_write, void, env, i32, i32)
>  DEF_HELPER_2(cpsr_write_eret, void, env, i32)
> diff --git a/target/arm/a32.decode b/target/arm/a32.decode
> index fcd8cd4f7d..f2ca480949 100644
> --- a/target/arm/a32.decode
> +++ b/target/arm/a32.decode
> @@ -187,13 +187,17 @@ SMULTT           .... 0001 0110 .... 0000 .... 1110 ....      @rd0mn
>
>  {
>    {
> -    YIELD        ---- 0011 0010 0000 1111 ---- 0000 0001
> -    WFE          ---- 0011 0010 0000 1111 ---- 0000 0010
> -    WFI          ---- 0011 0010 0000 1111 ---- 0000 0011
> +    [
> +      YIELD      ---- 0011 0010 0000 1111 ---- 0000 0001
> +      WFE        ---- 0011 0010 0000 1111 ---- 0000 0010
> +      WFI        ---- 0011 0010 0000 1111 ---- 0000 0011
>
> -    # TODO: Implement SEV, SEVL; may help SMP performance.
> -    # SEV        ---- 0011 0010 0000 1111 ---- 0000 0100
> -    # SEVL       ---- 0011 0010 0000 1111 ---- 0000 0101
> +      # TODO: Implement SEV, SEVL; may help SMP performance.
> +      # SEV      ---- 0011 0010 0000 1111 ---- 0000 0100
> +      # SEVL     ---- 0011 0010 0000 1111 ---- 0000 0101
> +
> +      ESB        ---- 0011 0010 0000 1111 ---- 0001 0000
> +    ]

Why don't we decode bits [11:8] here? I see it's the same
as YIELD/WFE/WFI, but I'm not sure why we're not decoding
those bits in those insns either...

>
>      # The canonical nop ends in 00000000, but the whole of the
>      # rest of the space executes as nop if otherwise unsupported.
> diff --git a/target/arm/t32.decode b/target/arm/t32.decode
> index 78fadef9d6..f21ad0167a 100644
> --- a/target/arm/t32.decode
> +++ b/target/arm/t32.decode
> @@ -364,17 +364,17 @@ CLZ              1111 1010 1011 ---- 1111 .... 1000 ....      @rdm
>    [
>      # Hints, and CPS
>      {
> -      YIELD      1111 0011 1010 1111 1000 0000 0000 0001
> -      WFE        1111 0011 1010 1111 1000 0000 0000 0010
> -      WFI        1111 0011 1010 1111 1000 0000 0000 0011
> +      [
> +        YIELD    1111 0011 1010 1111 1000 0000 0000 0001
> +        WFE      1111 0011 1010 1111 1000 0000 0000 0010
> +        WFI      1111 0011 1010 1111 1000 0000 0000 0011
>
> -      # TODO: Implement SEV, SEVL; may help SMP performance.
> -      # SEV      1111 0011 1010 1111 1000 0000 0000 0100
> -      # SEVL     1111 0011 1010 1111 1000 0000 0000 0101
> +        # TODO: Implement SEV, SEVL; may help SMP performance.
> +        # SEV    1111 0011 1010 1111 1000 0000 0000 0100
> +        # SEVL   1111 0011 1010 1111 1000 0000 0000 0101
>
> -      # For M-profile minimal-RAS ESB can be a NOP, which is the
> -      # default behaviour since it is in the hint space.
> -      # ESB      1111 0011 1010 1111 1000 0000 0001 0000
> +        ESB      1111 0011 1010 1111 1000 0000 0001 0000
> +      ]
>
>        # The canonical nop ends in 0000 0000, but the whole rest
>        # of the space is "reserved hint, behaves as nop".
> diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
> index 70b42b55fd..f50424b301 100644
> --- a/target/arm/op_helper.c
> +++ b/target/arm/op_helper.c
> @@ -972,3 +972,48 @@ void HELPER(probe_access)(CPUARMState *env, target_ulong ptr,
>                       access_type, mmu_idx, ra);
>      }
>  }
> +
> +void HELPER(esb)(CPUARMState *env)
> +{
> +    /*
> +     * QEMU does not have a source of physical SErrors, so we are
> +     * only concerned with virtual SErrors.
> +     *
> +     * During translation, we have already checked: RAS enabled,
> +     * EL2 present (enabled check done in arm_hcr_el2_eff), and
> +     * PSTATE.EL in {EL0, EL1}.  This function corresponds to
> +     * AArch64.vESBOperation(), noting that the AArch32 version
> +     * is not functionally different.
> +     */
> +    uint64_t hcr = arm_hcr_el2_eff(env);
> +    bool enabled = !(hcr & HCR_TGE) && (hcr & HCR_AMO);
> +    bool pending = enabled && (hcr & HCR_VSE);
> +    bool masked  = (env->daif & PSTATE_A);
> +
> +    /* If VSE pending and masked, defer the exception.  */
> +    if (pending && masked) {
> +        uint32_t syndrome;
> +
> +        if (arm_el_is_aa64(env, 1)) {
> +            /* Copy across IDS and ISS from VSESR. */
> +            syndrome = env->cp15.vsesr_el2 & 0x1ffffff;
> +        } else {
> +            ARMMMUFaultInfo fi = { .type = ARMFault_AsyncExternal };
> +
> +            if (extended_addresses_enabled(env)) {
> +                syndrome = arm_fi_to_lfsc(&fi);
> +            } else {
> +                syndrome = arm_fi_to_sfsc(&fi);
> +            }
> +            /* Copy across AET and ExT from VSESR. */
> +            syndrome |= env->cp15.vsesr_el2 & 0xd000;
> +        }
> +
> +        /* Set VDISR_EL2.A along with the syndrome. */
> +        env->cp15.vdisr_el2 = syndrome | (1u << 31);
> +
> +        /* Clear pending virtual SError */
> +        env->cp15.hcr_el2 &= ~HCR_VSE;
> +        cpu_reset_interrupt(env_cpu(env), CPU_INTERRUPT_VSERR);
> +    }
> +}
> diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
> index 9333d7be41..cc54dff83c 100644
> --- a/target/arm/translate-a64.c
> +++ b/target/arm/translate-a64.c
> @@ -1469,6 +1469,13 @@ static void handle_hint(DisasContext *s, uint32_t insn,
>              gen_helper_autib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
>          }
>          break;
> +    case 0b10000: /* ESB */
> +        if (dc_isar_feature(aa64_ras, s) &&
> +            arm_dc_feature(s, ARM_FEATURE_EL2) &&
> +            s->current_el <= 1) {
> +            gen_helper_esb(cpu_env);
> +        }
> +        break;
>      case 0b11000: /* PACIAZ */
>          if (s->pauth_active) {
>              gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30],
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index bf2196b9e2..b42ca53d99 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> @@ -6275,6 +6275,16 @@ static bool trans_WFI(DisasContext *s, arg_WFI *a)
>      return true;
>  }
>
> +static bool trans_ESB(DisasContext *s, arg_ESB *a)
> +{
> +    if (dc_isar_feature(aa32_ras, s) &&
> +        arm_dc_feature(s, ARM_FEATURE_EL2) &&
> +        s->current_el <= 1) {

This is doing the right thing for M-profile but only rather
indirectly because it happens to get caught by the FEATURE_EL2
check. I think it would be safer to explicitly check for
not-M-profile (which then gives you a place to put the
"For M-profile minimal-RAS ESB can be a NOP" comment that got
removed above).

> +        gen_helper_esb(cpu_env);
> +    }
> +    return true;

I think a comment noting that without RAS we must NOP would
be useful here.

> +}

Otherwise
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM
Richard Henderson April 11, 2022, 10:14 p.m. UTC | #2
On 4/11/22 09:18, Peter Maydell wrote:
>> +      ESB        ---- 0011 0010 0000 1111 ---- 0001 0000
>> +    ]
> 
> Why don't we decode bits [11:8] here? I see it's the same
> as YIELD/WFE/WFI, but I'm not sure why we're not decoding
> those bits in those insns either...

See page F4-7074 in H.a, where bits [11:8] of the imm12 field are described with 'xxxx'.

>> +static bool trans_ESB(DisasContext *s, arg_ESB *a)
>> +{
>> +    if (dc_isar_feature(aa32_ras, s) &&
>> +        arm_dc_feature(s, ARM_FEATURE_EL2) &&
>> +        s->current_el <= 1) {
> 
> This is doing the right thing for M-profile but only rather
> indirectly because it happens to get caught by the FEATURE_EL2
> check.

Yes, I had though that a feature, reducing the number of checks, but...


> I think it would be safer to explicitly check for
> not-M-profile (which then gives you a place to put the
> "For M-profile minimal-RAS ESB can be a NOP" comment that got
> removed above).

... fair enough.

> I think a comment noting that without RAS we must NOP would
> be useful here.

Ok.


r~
Peter Maydell April 12, 2022, 9:56 a.m. UTC | #3
On Mon, 11 Apr 2022 at 23:14, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 4/11/22 09:18, Peter Maydell wrote:
> >> +      ESB        ---- 0011 0010 0000 1111 ---- 0001 0000
> >> +    ]
> >
> > Why don't we decode bits [11:8] here? I see it's the same
> > as YIELD/WFE/WFI, but I'm not sure why we're not decoding
> > those bits in those insns either...
>
> See page F4-7074 in H.a, where bits [11:8] of the imm12 field are described with 'xxxx'.

Hmm. That just means "decodes to the NOP/WFI/ESB/whatever
instruction-description whatever the value of those bits",
but when the specific instruction-description then marks
those bits as "(0)" or "(1)", that has the usual CONSTRAINED
UNPREDICTABLE meaning described in section F1.7.2, where
we get a free choice of UNDEF, NOP, ignore the bit, or
any-dest-regs-are-UNKNOWN. So we're within the spec to
not decode [11:8] but I think it would be more consistent
with how we try to handle those (0) and (1) bits generally
if we insist that [11:8] is all zeroes here.

For this series, I guess go along with the current way we
handle hint instructions, and maybe fix this as a separate
cleanup later.

-- PMM
Richard Henderson April 12, 2022, 2:31 p.m. UTC | #4
On 4/12/22 02:56, Peter Maydell wrote:
> On Mon, 11 Apr 2022 at 23:14, Richard Henderson
> <richard.henderson@linaro.org> wrote:
>>
>> On 4/11/22 09:18, Peter Maydell wrote:
>>>> +      ESB        ---- 0011 0010 0000 1111 ---- 0001 0000
>>>> +    ]
>>>
>>> Why don't we decode bits [11:8] here? I see it's the same
>>> as YIELD/WFE/WFI, but I'm not sure why we're not decoding
>>> those bits in those insns either...
>>
>> See page F4-7074 in H.a, where bits [11:8] of the imm12 field are described with 'xxxx'.
> 
> Hmm. That just means "decodes to the NOP/WFI/ESB/whatever
> instruction-description whatever the value of those bits",
> but when the specific instruction-description then marks
> those bits as "(0)" or "(1)", that has the usual CONSTRAINED
> UNPREDICTABLE meaning described in section F1.7.2, where
> we get a free choice of UNDEF, NOP, ignore the bit, or
> any-dest-regs-are-UNKNOWN. So we're within the spec to
> not decode [11:8] but I think it would be more consistent
> with how we try to handle those (0) and (1) bits generally
> if we insist that [11:8] is all zeroes here.
> 
> For this series, I guess go along with the current way we
> handle hint instructions, and maybe fix this as a separate
> cleanup later.

Ok.

r~
diff mbox series

Patch

diff --git a/target/arm/helper.h b/target/arm/helper.h
index b463d9343b..bb7f901668 100644
--- a/target/arm/helper.h
+++ b/target/arm/helper.h
@@ -54,6 +54,7 @@  DEF_HELPER_1(wfe, void, env)
 DEF_HELPER_1(yield, void, env)
 DEF_HELPER_1(pre_hvc, void, env)
 DEF_HELPER_2(pre_smc, void, env, i32)
+DEF_HELPER_1(esb, void, env)
 
 DEF_HELPER_3(cpsr_write, void, env, i32, i32)
 DEF_HELPER_2(cpsr_write_eret, void, env, i32)
diff --git a/target/arm/a32.decode b/target/arm/a32.decode
index fcd8cd4f7d..f2ca480949 100644
--- a/target/arm/a32.decode
+++ b/target/arm/a32.decode
@@ -187,13 +187,17 @@  SMULTT           .... 0001 0110 .... 0000 .... 1110 ....      @rd0mn
 
 {
   {
-    YIELD        ---- 0011 0010 0000 1111 ---- 0000 0001
-    WFE          ---- 0011 0010 0000 1111 ---- 0000 0010
-    WFI          ---- 0011 0010 0000 1111 ---- 0000 0011
+    [
+      YIELD      ---- 0011 0010 0000 1111 ---- 0000 0001
+      WFE        ---- 0011 0010 0000 1111 ---- 0000 0010
+      WFI        ---- 0011 0010 0000 1111 ---- 0000 0011
 
-    # TODO: Implement SEV, SEVL; may help SMP performance.
-    # SEV        ---- 0011 0010 0000 1111 ---- 0000 0100
-    # SEVL       ---- 0011 0010 0000 1111 ---- 0000 0101
+      # TODO: Implement SEV, SEVL; may help SMP performance.
+      # SEV      ---- 0011 0010 0000 1111 ---- 0000 0100
+      # SEVL     ---- 0011 0010 0000 1111 ---- 0000 0101
+
+      ESB        ---- 0011 0010 0000 1111 ---- 0001 0000
+    ]
 
     # The canonical nop ends in 00000000, but the whole of the
     # rest of the space executes as nop if otherwise unsupported.
diff --git a/target/arm/t32.decode b/target/arm/t32.decode
index 78fadef9d6..f21ad0167a 100644
--- a/target/arm/t32.decode
+++ b/target/arm/t32.decode
@@ -364,17 +364,17 @@  CLZ              1111 1010 1011 ---- 1111 .... 1000 ....      @rdm
   [
     # Hints, and CPS
     {
-      YIELD      1111 0011 1010 1111 1000 0000 0000 0001
-      WFE        1111 0011 1010 1111 1000 0000 0000 0010
-      WFI        1111 0011 1010 1111 1000 0000 0000 0011
+      [
+        YIELD    1111 0011 1010 1111 1000 0000 0000 0001
+        WFE      1111 0011 1010 1111 1000 0000 0000 0010
+        WFI      1111 0011 1010 1111 1000 0000 0000 0011
 
-      # TODO: Implement SEV, SEVL; may help SMP performance.
-      # SEV      1111 0011 1010 1111 1000 0000 0000 0100
-      # SEVL     1111 0011 1010 1111 1000 0000 0000 0101
+        # TODO: Implement SEV, SEVL; may help SMP performance.
+        # SEV    1111 0011 1010 1111 1000 0000 0000 0100
+        # SEVL   1111 0011 1010 1111 1000 0000 0000 0101
 
-      # For M-profile minimal-RAS ESB can be a NOP, which is the
-      # default behaviour since it is in the hint space.
-      # ESB      1111 0011 1010 1111 1000 0000 0001 0000
+        ESB      1111 0011 1010 1111 1000 0000 0001 0000
+      ]
 
       # The canonical nop ends in 0000 0000, but the whole rest
       # of the space is "reserved hint, behaves as nop".
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index 70b42b55fd..f50424b301 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -972,3 +972,48 @@  void HELPER(probe_access)(CPUARMState *env, target_ulong ptr,
                      access_type, mmu_idx, ra);
     }
 }
+
+void HELPER(esb)(CPUARMState *env)
+{
+    /*
+     * QEMU does not have a source of physical SErrors, so we are
+     * only concerned with virtual SErrors.
+     *
+     * During translation, we have already checked: RAS enabled,
+     * EL2 present (enabled check done in arm_hcr_el2_eff), and
+     * PSTATE.EL in {EL0, EL1}.  This function corresponds to
+     * AArch64.vESBOperation(), noting that the AArch32 version
+     * is not functionally different.
+     */
+    uint64_t hcr = arm_hcr_el2_eff(env);
+    bool enabled = !(hcr & HCR_TGE) && (hcr & HCR_AMO);
+    bool pending = enabled && (hcr & HCR_VSE);
+    bool masked  = (env->daif & PSTATE_A);
+
+    /* If VSE pending and masked, defer the exception.  */
+    if (pending && masked) {
+        uint32_t syndrome;
+
+        if (arm_el_is_aa64(env, 1)) {
+            /* Copy across IDS and ISS from VSESR. */
+            syndrome = env->cp15.vsesr_el2 & 0x1ffffff;
+        } else {
+            ARMMMUFaultInfo fi = { .type = ARMFault_AsyncExternal };
+
+            if (extended_addresses_enabled(env)) {
+                syndrome = arm_fi_to_lfsc(&fi);
+            } else {
+                syndrome = arm_fi_to_sfsc(&fi);
+            }
+            /* Copy across AET and ExT from VSESR. */
+            syndrome |= env->cp15.vsesr_el2 & 0xd000;
+        }
+
+        /* Set VDISR_EL2.A along with the syndrome. */
+        env->cp15.vdisr_el2 = syndrome | (1u << 31);
+
+        /* Clear pending virtual SError */
+        env->cp15.hcr_el2 &= ~HCR_VSE;
+        cpu_reset_interrupt(env_cpu(env), CPU_INTERRUPT_VSERR);
+    }
+}
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 9333d7be41..cc54dff83c 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -1469,6 +1469,13 @@  static void handle_hint(DisasContext *s, uint32_t insn,
             gen_helper_autib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
         }
         break;
+    case 0b10000: /* ESB */
+        if (dc_isar_feature(aa64_ras, s) &&
+            arm_dc_feature(s, ARM_FEATURE_EL2) &&
+            s->current_el <= 1) {
+            gen_helper_esb(cpu_env);
+        }
+        break;
     case 0b11000: /* PACIAZ */
         if (s->pauth_active) {
             gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30],
diff --git a/target/arm/translate.c b/target/arm/translate.c
index bf2196b9e2..b42ca53d99 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -6275,6 +6275,16 @@  static bool trans_WFI(DisasContext *s, arg_WFI *a)
     return true;
 }
 
+static bool trans_ESB(DisasContext *s, arg_ESB *a)
+{
+    if (dc_isar_feature(aa32_ras, s) &&
+        arm_dc_feature(s, ARM_FEATURE_EL2) &&
+        s->current_el <= 1) {
+        gen_helper_esb(cpu_env);
+    }
+    return true;
+}
+
 static bool trans_NOP(DisasContext *s, arg_NOP *a)
 {
     return true;