diff mbox series

[1/2] target/arm: add support for FEAT_DIT, Data Independent Timing

Message ID 20201211051359.3231-2-rebecca@nuviainc.com
State New
Headers show
Series target/arm: Add support for DIT (Data Independent Timing) | expand

Commit Message

Rebecca Cran Dec. 11, 2020, 5:13 a.m. UTC
Add support for FEAT_DIT. DIT (Data Independent Timing) is a required
feature for ARMv8.4. Since virtual machine execution is largely
nondeterministic, it's implemented as a NOP.

Signed-off-by: Rebecca Cran <rebecca@nuviainc.com>
---
 target/arm/cpu.h           | 20 +++++++++++++-
 target/arm/helper.c        | 28 +++++++++++++++++++-
 target/arm/internals.h     |  6 +++++
 target/arm/translate-a64.c | 14 ++++++++++
 4 files changed, 66 insertions(+), 2 deletions(-)

Comments

Richard Henderson Dec. 11, 2020, 2:08 p.m. UTC | #1
On 12/10/20 11:13 PM, Rebecca Cran wrote:
> Add support for FEAT_DIT. DIT (Data Independent Timing) is a required
> feature for ARMv8.4. Since virtual machine execution is largely
> nondeterministic, it's implemented as a NOP.

Alternately, or additionally, TCG is outside of the security domain (only
hardware accelerators like KVM are inside), and so we may implement this as a NOP.

> 
> Signed-off-by: Rebecca Cran <rebecca@nuviainc.com>
> ---
>  target/arm/cpu.h           | 20 +++++++++++++-
>  target/arm/helper.c        | 28 +++++++++++++++++++-
>  target/arm/internals.h     |  6 +++++
>  target/arm/translate-a64.c | 14 ++++++++++
>  4 files changed, 66 insertions(+), 2 deletions(-)
> 
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index 4c9cbfbd9975..862be662cef7 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -269,6 +269,7 @@ typedef struct CPUARMState {
>      uint32_t NF; /* N is bit 31. All other bits are undefined.  */
>      uint32_t ZF; /* Z set if zero.  */
>      uint32_t QF; /* 0 or 1 */
> +    uint32_t DIT; /* 0 or 1 */

You don't need to add this.  Leave the DIT bit in uncached_cpsr.

> +++ b/target/arm/translate-a64.c
> @@ -1696,6 +1696,20 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
>          tcg_temp_free_i32(t1);
>          break;
>  
> +    case 0x1a: /* DIT */
> +        if (!dc_isar_feature(aa64_dit, s)) {
> +            goto do_unallocated;
> +        }
> +        if (crm & 1) {
> +            set_pstate_bits(PSTATE_DIT);
> +        } else {
> +            clear_pstate_bits(PSTATE_DIT);
> +        }
> +        t1 = tcg_const_i32(s->current_el);
> +        gen_helper_rebuild_hflags_a64(cpu_env, t1);
> +        tcg_temp_free_i32(t1);
> +        break;

You don't need to rebuild hflags, because the implementation of DIT is a nop.
All you need is to record the pstate change.  You may wish to add a comment
here about that, reminding the reader.


r~
Rebecca Cran Dec. 11, 2020, 7:33 p.m. UTC | #2
On 12/11/20 7:08 AM, Richard Henderson wrote:
> Alternately, or additionally, TCG is outside of the security domain (only
> hardware accelerators like KVM are inside), and so we may implement this as a NOP.

Thanks for the feedback, I'll send a v2 patch next week.


Is the comment in target/arm/op_helper.c:397 still relevant?


uint32_t HELPER(cpsr_read)(CPUARMState *env)
{
     /*
      * We store the ARMv8 PSTATE.SS bit in env->uncached_cpsr.
      * This is convenient for populating SPSR_ELx, but must be
      * hidden from aarch32 mode, where it is not visible.
      *
      * TODO: ARMv8.4-DIT -- need to move SS somewhere else.
      */
     return cpsr_read(env) & ~(CPSR_EXEC | PSTATE_SS);
}
Richard Henderson Dec. 11, 2020, 7:51 p.m. UTC | #3
On 12/11/20 1:33 PM, Rebecca Cran wrote:
> Is the comment in target/arm/op_helper.c:397 still relevant?
> 
> uint32_t HELPER(cpsr_read)(CPUARMState *env)
> {
>     /*
>      * We store the ARMv8 PSTATE.SS bit in env->uncached_cpsr.
>      * This is convenient for populating SPSR_ELx, but must be
>      * hidden from aarch32 mode, where it is not visible.
>      *
>      * TODO: ARMv8.4-DIT -- need to move SS somewhere else.
>      */
>     return cpsr_read(env) & ~(CPSR_EXEC | PSTATE_SS);
> }

I forgot about this.  So we can't "just" store DIT in uncached_cpsr.

I'll let Peter weigh in, but I think it makes sense to move the SS bit
somewhere else (e.g. env->pstate) and merge it into SPSR_ELx upon interrupt.
While what we're doing here is convenient, it's not architectural, and it would
be better to follow GetPSRFromPSTATE pseudocode.


r~
Peter Maydell Dec. 11, 2020, 9:37 p.m. UTC | #4
On Fri, 11 Dec 2020 at 19:51, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 12/11/20 1:33 PM, Rebecca Cran wrote:
> > Is the comment in target/arm/op_helper.c:397 still relevant?
> >
> > uint32_t HELPER(cpsr_read)(CPUARMState *env)
> > {
> >     /*
> >      * We store the ARMv8 PSTATE.SS bit in env->uncached_cpsr.
> >      * This is convenient for populating SPSR_ELx, but must be
> >      * hidden from aarch32 mode, where it is not visible.
> >      *
> >      * TODO: ARMv8.4-DIT -- need to move SS somewhere else.
> >      */
> >     return cpsr_read(env) & ~(CPSR_EXEC | PSTATE_SS);
> > }
>
> I forgot about this.  So we can't "just" store DIT in uncached_cpsr.
>
> I'll let Peter weigh in, but I think it makes sense to move the SS bit
> somewhere else (e.g. env->pstate) and merge it into SPSR_ELx upon interrupt.
> While what we're doing here is convenient, it's not architectural, and it would
> be better to follow GetPSRFromPSTATE pseudocode.

Yes, I think that's the best thing to do. We've been skating
by on CPSR and SPSR being the same thing and it's just
stopped working.

-- PMM
Rebecca Cran Dec. 14, 2020, 6:11 p.m. UTC | #5
On 12/11/20 2:37 PM, Peter Maydell wrote:
> On Fri, 11 Dec 2020 at 19:51, Richard Henderson
> <richard.henderson@linaro.org> wrote:
>> I'll let Peter weigh in, but I think it makes sense to move the SS bit
>> somewhere else (e.g. env->pstate) and merge it into SPSR_ELx upon interrupt.
>> While what we're doing here is convenient, it's not architectural, and it would
>> be better to follow GetPSRFromPSTATE pseudocode.
> 
> Yes, I think that's the best thing to do. We've been skating
> by on CPSR and SPSR being the same thing and it's just
> stopped working.


Would you like me to work on this, or is it something the arm 
maintainers would fix?
Peter Maydell Dec. 14, 2020, 6:48 p.m. UTC | #6
On Mon, 14 Dec 2020 at 18:11, Rebecca Cran <rebecca@nuviainc.com> wrote:
>
> On 12/11/20 2:37 PM, Peter Maydell wrote:
> > On Fri, 11 Dec 2020 at 19:51, Richard Henderson
> > <richard.henderson@linaro.org> wrote:
> >> I'll let Peter weigh in, but I think it makes sense to move the SS bit
> >> somewhere else (e.g. env->pstate) and merge it into SPSR_ELx upon interrupt.
> >> While what we're doing here is convenient, it's not architectural, and it would
> >> be better to follow GetPSRFromPSTATE pseudocode.
> >
> > Yes, I think that's the best thing to do. We've been skating
> > by on CPSR and SPSR being the same thing and it's just
> > stopped working.
>
> Would you like me to work on this, or is it something the arm
> maintainers would fix?

You're the person that wants to add the change that
requires this refactoring, so if you could, I think the
best thing would be for you to do this bit of work
and send it as part of this patchseries.

thanks
-- PMM
diff mbox series

Patch

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 4c9cbfbd9975..862be662cef7 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -269,6 +269,7 @@  typedef struct CPUARMState {
     uint32_t NF; /* N is bit 31. All other bits are undefined.  */
     uint32_t ZF; /* Z set if zero.  */
     uint32_t QF; /* 0 or 1 */
+    uint32_t DIT; /* 0 or 1 */
     uint32_t GE; /* cpsr[19:16] */
     uint32_t thumb; /* cpsr[5]. 0 = arm mode, 1 = thumb mode. */
     uint32_t condexec_bits; /* IT bits.  cpsr[15:10,26:25].  */
@@ -1233,6 +1234,7 @@  void pmu_init(ARMCPU *cpu);
 #define CPSR_IT_2_7 (0xfc00U)
 #define CPSR_GE (0xfU << 16)
 #define CPSR_IL (1U << 20)
+#define CPSR_DIT (1U << 21)
 #define CPSR_PAN (1U << 22)
 #define CPSR_J (1U << 24)
 #define CPSR_IT_0_1 (3U << 25)
@@ -1266,6 +1268,7 @@  void pmu_init(ARMCPU *cpu);
 #define XPSR_Z CPSR_Z
 #define XPSR_N CPSR_N
 #define XPSR_NZCV CPSR_NZCV
+#define XPSR_DIT CPSR_DIT
 #define XPSR_IT CPSR_IT
 
 #define TTBCR_N      (7U << 0) /* TTBCR.EAE==0 */
@@ -1300,6 +1303,7 @@  void pmu_init(ARMCPU *cpu);
 #define PSTATE_SS (1U << 21)
 #define PSTATE_PAN (1U << 22)
 #define PSTATE_UAO (1U << 23)
+#define PSTATE_DIT (1U << 24)
 #define PSTATE_TCO (1U << 25)
 #define PSTATE_V (1U << 28)
 #define PSTATE_C (1U << 29)
@@ -1374,7 +1378,8 @@  static inline uint32_t xpsr_read(CPUARMState *env)
     ZF = (env->ZF == 0);
     return (env->NF & 0x80000000) | (ZF << 30)
         | (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27)
-        | (env->thumb << 24) | ((env->condexec_bits & 3) << 25)
+        | (env->thumb << 24) | (env->DIT << 21)
+        | ((env->condexec_bits & 3) << 25)
         | ((env->condexec_bits & 0xfc) << 8)
         | (env->GE << 16)
         | env->v7m.exception;
@@ -1389,6 +1394,9 @@  static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
         env->CF = (val >> 29) & 1;
         env->VF = (val << 3) & 0x80000000;
     }
+    if (mask & XPSR_DIT) {
+        env->DIT = ((val & XPSR_DIT) != 0);
+    }
     if (mask & XPSR_Q) {
         env->QF = ((val & XPSR_Q) != 0);
     }
@@ -3823,6 +3831,11 @@  static inline bool isar_feature_aa32_tts2uxn(const ARMISARegisters *id)
     return FIELD_EX32(id->id_mmfr4, ID_MMFR4, XNX) != 0;
 }
 
+static inline bool isar_feature_aa32_dit(const ARMISARegisters *id)
+{
+    return FIELD_EX32(id->id_pfr0, ID_PFR0, DIT) != 0;
+}
+
 /*
  * 64-bit feature tests via id registers.
  */
@@ -4050,6 +4063,11 @@  static inline bool isar_feature_aa64_tts2uxn(const ARMISARegisters *id)
     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, XNX) != 0;
 }
 
+static inline bool isar_feature_aa64_dit(const ARMISARegisters *id)
+{
+    return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, DIT) != 0;
+}
+
 /*
  * Feature tests for "does this exist in either 32-bit or 64-bit?"
  */
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 7b8bcd69030f..eb4979baceff 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -4390,6 +4390,24 @@  static const ARMCPRegInfo uao_reginfo = {
     .readfn = aa64_uao_read, .writefn = aa64_uao_write
 };
 
+static uint64_t aa64_dit_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    return env->pstate & PSTATE_DIT;
+}
+
+static void aa64_dit_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                           uint64_t value)
+{
+    env->pstate = (env->pstate & ~PSTATE_DIT) | (value & PSTATE_DIT);
+}
+
+static const ARMCPRegInfo dit_reginfo = {
+    .name = "DIT", .state = ARM_CP_STATE_AA64,
+    .opc0 = 3, .opc1 = 3, .crn = 4, .crm = 2, .opc2 = 5,
+    .type = ARM_CP_NO_RAW, .access = PL0_RW,
+    .readfn = aa64_dit_read, .writefn = aa64_dit_write
+};
+
 static CPAccessResult aa64_cacheop_poc_access(CPUARMState *env,
                                               const ARMCPRegInfo *ri,
                                               bool isread)
@@ -8133,6 +8151,10 @@  void register_cp_regs_for_features(ARMCPU *cpu)
         define_one_arm_cp_reg(cpu, &uao_reginfo);
     }
 
+    if (cpu_isar_feature(aa64_dit, cpu)) {
+        define_one_arm_cp_reg(cpu, &dit_reginfo);
+    }
+
     if (arm_feature(env, ARM_FEATURE_EL2) && cpu_isar_feature(aa64_vh, cpu)) {
         define_arm_cp_regs(cpu, vhe_reginfo);
     }
@@ -8740,7 +8762,8 @@  uint32_t cpsr_read(CPUARMState *env)
     ZF = (env->ZF == 0);
     return env->uncached_cpsr | (env->NF & 0x80000000) | (ZF << 30) |
         (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27)
-        | (env->thumb << 5) | ((env->condexec_bits & 3) << 25)
+        | (env->DIT << 21) | (env->thumb << 5)
+        | ((env->condexec_bits & 3) << 25)
         | ((env->condexec_bits & 0xfc) << 8)
         | (env->GE << 16) | (env->daif & CPSR_AIF);
 }
@@ -8756,6 +8779,9 @@  void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask,
         env->CF = (val >> 29) & 1;
         env->VF = (val << 3) & 0x80000000;
     }
+    if (mask & CPSR_DIT) {
+        env->DIT = ((val & CPSR_DIT) != 0);
+    }
     if (mask & CPSR_Q)
         env->QF = ((val & CPSR_Q) != 0);
     if (mask & CPSR_T)
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 5460678756d3..00ecfc174c80 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1186,6 +1186,9 @@  static inline uint32_t aarch32_cpsr_valid_mask(uint64_t features,
     if (isar_feature_aa32_pan(id)) {
         valid |= CPSR_PAN;
     }
+    if (isar_feature_aa32_dit(id)) {
+        valid |= CPSR_DIT;
+    }
 
     return valid;
 }
@@ -1204,6 +1207,9 @@  static inline uint32_t aarch64_pstate_valid_mask(const ARMISARegisters *id)
     if (isar_feature_aa64_uao(id)) {
         valid |= PSTATE_UAO;
     }
+    if (isar_feature_aa64_dit(id)) {
+        valid |= PSTATE_DIT;
+    }
     if (isar_feature_aa64_mte(id)) {
         valid |= PSTATE_TCO;
     }
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 2e3fdfdf6ba8..0cafba6188c6 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -1696,6 +1696,20 @@  static void handle_msr_i(DisasContext *s, uint32_t insn,
         tcg_temp_free_i32(t1);
         break;
 
+    case 0x1a: /* DIT */
+        if (!dc_isar_feature(aa64_dit, s)) {
+            goto do_unallocated;
+        }
+        if (crm & 1) {
+            set_pstate_bits(PSTATE_DIT);
+        } else {
+            clear_pstate_bits(PSTATE_DIT);
+        }
+        t1 = tcg_const_i32(s->current_el);
+        gen_helper_rebuild_hflags_a64(cpu_env, t1);
+        tcg_temp_free_i32(t1);
+        break;
+
     case 0x1e: /* DAIFSet */
         t1 = tcg_const_i32(crm);
         gen_helper_msr_i_daifset(cpu_env, t1);