diff mbox

[v2,02/10] target-arm/cpu.h: common pstate save/restore

Message ID 1405007407-23549-3-git-send-email-alex.bennee@linaro.org
State New
Headers show

Commit Message

Alex Bennée July 10, 2014, 3:49 p.m. UTC
This adds a universal program state save and restore function. This is
intended to simplify the migration serialisation functionality and avoid
special casing depending on the mode of the CPU at serialisation time.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v2:
  - reword commentary for restore_state_from_spsr
  - rm commented out code
  - add set_condition_codes for flags
  - add xpsr_read functionality

v3:
  - rebase
  - checkpatch.pl issues

Comments

Peter Maydell Aug. 4, 2014, 12:47 p.m. UTC | #1
On 10 July 2014 16:49, Alex Bennée <alex.bennee@linaro.org> wrote:
> This adds a universal program state save and restore function. This is
> intended to simplify the migration serialisation functionality and avoid
> special casing depending on the mode of the CPU at serialisation time.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>
> ---
> v2:
>   - reword commentary for restore_state_from_spsr
>   - rm commented out code
>   - add set_condition_codes for flags
>   - add xpsr_read functionality
>
> v3:
>   - rebase
>   - checkpatch.pl issues
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index c2312d0..fe4d4f3 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -453,19 +453,24 @@ int arm_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
>  #define PSTATE_SP (1U)
>  #define PSTATE_M (0xFU)
>  #define PSTATE_nRW (1U << 4)
> +#define PSTATE_T (1U << 5)
>  #define PSTATE_F (1U << 6)
>  #define PSTATE_I (1U << 7)
>  #define PSTATE_A (1U << 8)
>  #define PSTATE_D (1U << 9)
>  #define PSTATE_IL (1U << 20)
>  #define PSTATE_SS (1U << 21)
> +#define PSTATE_Q (1U << 27)
>  #define PSTATE_V (1U << 28)
>  #define PSTATE_C (1U << 29)
>  #define PSTATE_Z (1U << 30)
>  #define PSTATE_N (1U << 31)
>  #define PSTATE_NZCV (PSTATE_N | PSTATE_Z | PSTATE_C | PSTATE_V)
> -#define PSTATE_DAIF (PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F)
> -#define CACHED_PSTATE_BITS (PSTATE_NZCV | PSTATE_DAIF)
> +#define PSTATE_AIF  (PSTATE_A | PSTATE_I | PSTATE_F)
> +#define PSTATE_DAIF (PSTATE_D | PSTATE_AIF)
> +#define AARCH64_CACHED_PSTATE_BITS (PSTATE_NZCV | PSTATE_DAIF)
> +#define AARCH32_CACHED_PSTATE_BITS (PSTATE_NZCV | PSTATE_Q | PSTATE_AIF \
> +                                    | CACHED_CPSR_BITS)
>  /* Mode values for AArch64 */
>  #define PSTATE_MODE_EL3h 13
>  #define PSTATE_MODE_EL3t 12
> @@ -508,7 +513,7 @@ static inline void pstate_write(CPUARMState *env, uint32_t val)
>      env->CF = (val >> 29) & 1;
>      env->VF = (val << 3) & 0x80000000;
>      env->daif = val & PSTATE_DAIF;
> -    env->pstate = val & ~CACHED_PSTATE_BITS;
> +    env->pstate = val & ~AARCH64_CACHED_PSTATE_BITS;
>  }
>
>  /* ARMv7-AR ARM B1.3.3 Current Program Status Register, CPSR
> @@ -698,6 +703,137 @@ static inline bool arm_el_is_aa64(CPUARMState *env, int el)
>      return arm_feature(env, ARM_FEATURE_AARCH64);
>  }
>
> +/* ARMv8 ARM D1.6.4, Saved Program Status Registers
> + *
> + * These are formats used to save program status when exceptions are
> + * taken. There are two forms:
> + *
> + * AArch64 -> AArch64 Exception
> + *  31  30  28  29  27  22  21   20  19  10  9   8   7   6   5  4   3      0
> + * +---+---+---+---+------+----+----+------+---+---+---+---+---+------------+
> + * | N | Z | C | V | RES0 | SS | IL | RES0 | D | A | I | F | 0 | 0 | M[3:0] |
> + * +---+---+---+---+------+----+----+------+---+---+---+---+---+------------+
> + *
> + * AArch32 -> AArch64 Exception
> + * (see also ARMv7-AR ARM B1.3.3 CSPR/SPSR formats)
> + *  31  30  29  28  27  26     25 24  23  22  21   20  19     16
> + * +---+---+---+---+---+---------+---+------+----+----+---------+
> + * | N | Z | C | V | Q | IT[1:0] | J | RES0 | SS | IL | GE[3:0] |
> + * +---+---+---+---+---+---------+---+------+----+----+---------+
> + *  15     10  9   8   7   6   5   4  3      0
> + * +---------+---+---+---+---+---+---+--------+
> + * | IT[7:2] | E | A | I | F | T | 1 | M[3:0] |
> + * +---------+---+---+---+---+---+---+--------+
> + *
> + * M[4] = nRW - 0 = 64bit, 1 = 32bit
> + * Bit definitions for ARMv8 SPSR (PSTATE) format.
> + * Only these are valid when in AArch64 mode; in
> + * AArch32 mode SPSRs are basically CPSR-format.
> + *
> + * Also ARMv7-M ARM B1.4.2, special purpose program status register xPSR
> + */
> +
> +/* Save the program state */
> +static inline uint32_t save_state_to_spsr(CPUARMState *env)
> +{
> +    uint32_t final_spsr = 0;
> +
> +    /* Calculate integer flags */
> +    final_spsr |= (env->NF & 0x80000000) ? PSTATE_N : 0; /* bit 31 */
> +    final_spsr |= (env->ZF == 0) ? PSTATE_Z : 0;
> +    final_spsr |= env->CF ? PSTATE_C : 0;                /* or env->CF << 29 */
> +    final_spsr |= (env->VF & 0x80000000) ? PSTATE_V : 0; /* bit 31 */
> +
> +    if (is_a64(env)) {
> +        /* SS - Software Step */
> +        /* IL - Illegal execution state */

Not sure you need specific comments here for SS and IL -- I
would expect those to live in env->pstate with the other
uncached bits.

> +        /* DAIF flags - should we mask?*/
> +        final_spsr |= (env->daif & PSTATE_DAIF);

We don't mask env->daif in pstate_read() so we don't need to
here either.

> +        /* And the final un-cached bits */
> +        final_spsr |= (env->pstate & ~AARCH64_CACHED_PSTATE_BITS);
> +    } else {
> +        /* condexec_bits is split over two parts */
> +        final_spsr |= ((env->condexec_bits & 3) << 25);
> +        final_spsr |= ((env->condexec_bits & 0xfc) << 8);
> +
> +        if (arm_feature(env, ARM_FEATURE_M)) {
> +            final_spsr |= (env->thumb << 24);   /* alt pos */

This comment is too cryptic.

> +            final_spsr |= env->v7m.exception;
> +        } else {
> +            final_spsr |= env->QF ? PSTATE_Q : 0;
> +            /* GE needs shifting into place */
> +            final_spsr |= (env->GE << 16);
> +            /* AIF is a a subset of DAIF */

More interesting would be to point out that the D bit doesn't
exist in an AArch32 SPSR and it's used for the E bit instead.

> +            final_spsr |= (env->daif & PSTATE_AIF);
> +            final_spsr |= env->thumb ? PSTATE_T : 0;
> +
> +            final_spsr |= PSTATE_nRW;
> +
> +            /* And the final un-cached bits */
> +            final_spsr |= (env->uncached_cpsr & ~AARCH32_CACHED_PSTATE_BITS);
> +        }
> +    }
> +    return final_spsr;
> +}
> +
> +/* Restore the program state.
> + *
> + * This restores the program execution state including it's current

"its"

> + * execution mode. However validation of mode changes and additional
> + * registers and state that need changing should be done by the
> + * calling function.
> + *
> + * The simple set_condition_codes() function can be used just to
> + * update the cached integer flags which are quite often manipulated
> + * alone.
> + */
> +
> +/* Only update the cached condition codes. */
> +static inline void set_condition_codes(CPUARMState *env, uint32_t new_flags)
> +{
> +    /* Process the integer flags directly */
> +    env->ZF = (~new_flags) & CPSR_Z;
> +    env->NF = new_flags;
> +    env->CF = (new_flags >> 29) & 1;
> +    env->VF = (new_flags << 3) & 0x80000000;
> +}
> +
> +/* Restore the complete program state */
> +static inline void restore_state_from_spsr(CPUARMState *env,
> +                                           uint32_t saved_state)
> +{
> +    set_condition_codes(env, saved_state);
> +
> +    /* the rest depends on the mode we end up in */
> +    env->aarch64 = (saved_state & PSTATE_nRW) ? 0 : 1;
> +
> +    if (is_a64(env)) {
> +        env->daif = saved_state & PSTATE_DAIF;
> +        env->pstate = (saved_state & ~AARCH64_CACHED_PSTATE_BITS);
> +    } else {
> +        if (arm_feature(env, ARM_FEATURE_M)) {
> +            fprintf(stderr, "%s: M state not yet implmented\n", __func__);
> +        } else {
> +            env->QF = saved_state & PSTATE_Q ? 1 : 0;
> +            /* condexec_bits is split over two parts */
> +            env->condexec_bits = (saved_state & CPSR_IT_0_1) >> 25;
> +            env->condexec_bits |= (saved_state & CPSR_IT_2_7) >> 8;
> +
> +            /* GE needs shifting into place */
> +            env->GE = (saved_state >> 16) & 0xf;
> +
> +            /* AIF is a a subset of DAIF */
> +            env->daif = (saved_state & PSTATE_AIF);

The interesting bit here is that PSTATE.D is not accessible
(directly or indirectly by having it affect behaviour) in AArch32,
so it has an undefined value. We're choosing to set it to zero
here for consistency/to avoid being confusing.

> +
> +            env->thumb = saved_state & PSTATE_T ? 1 : 0;
> +
> +            /* And the final un-cached bits */
> +            env->uncached_cpsr = saved_state & ~AARCH32_CACHED_PSTATE_BITS;
> +        }
> +    }
> +}
> +
> +

Stray blank line.

>  void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
>
>  /* Interface between CPU and Interrupt controller.  */
> --
> 2.0.1

thanks
-- PMM
diff mbox

Patch

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c2312d0..fe4d4f3 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -453,19 +453,24 @@  int arm_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
 #define PSTATE_SP (1U)
 #define PSTATE_M (0xFU)
 #define PSTATE_nRW (1U << 4)
+#define PSTATE_T (1U << 5)
 #define PSTATE_F (1U << 6)
 #define PSTATE_I (1U << 7)
 #define PSTATE_A (1U << 8)
 #define PSTATE_D (1U << 9)
 #define PSTATE_IL (1U << 20)
 #define PSTATE_SS (1U << 21)
+#define PSTATE_Q (1U << 27)
 #define PSTATE_V (1U << 28)
 #define PSTATE_C (1U << 29)
 #define PSTATE_Z (1U << 30)
 #define PSTATE_N (1U << 31)
 #define PSTATE_NZCV (PSTATE_N | PSTATE_Z | PSTATE_C | PSTATE_V)
-#define PSTATE_DAIF (PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F)
-#define CACHED_PSTATE_BITS (PSTATE_NZCV | PSTATE_DAIF)
+#define PSTATE_AIF  (PSTATE_A | PSTATE_I | PSTATE_F)
+#define PSTATE_DAIF (PSTATE_D | PSTATE_AIF)
+#define AARCH64_CACHED_PSTATE_BITS (PSTATE_NZCV | PSTATE_DAIF)
+#define AARCH32_CACHED_PSTATE_BITS (PSTATE_NZCV | PSTATE_Q | PSTATE_AIF \
+                                    | CACHED_CPSR_BITS)
 /* Mode values for AArch64 */
 #define PSTATE_MODE_EL3h 13
 #define PSTATE_MODE_EL3t 12
@@ -508,7 +513,7 @@  static inline void pstate_write(CPUARMState *env, uint32_t val)
     env->CF = (val >> 29) & 1;
     env->VF = (val << 3) & 0x80000000;
     env->daif = val & PSTATE_DAIF;
-    env->pstate = val & ~CACHED_PSTATE_BITS;
+    env->pstate = val & ~AARCH64_CACHED_PSTATE_BITS;
 }
 
 /* ARMv7-AR ARM B1.3.3 Current Program Status Register, CPSR
@@ -698,6 +703,137 @@  static inline bool arm_el_is_aa64(CPUARMState *env, int el)
     return arm_feature(env, ARM_FEATURE_AARCH64);
 }
 
+/* ARMv8 ARM D1.6.4, Saved Program Status Registers
+ *
+ * These are formats used to save program status when exceptions are
+ * taken. There are two forms:
+ *
+ * AArch64 -> AArch64 Exception
+ *  31  30  28  29  27  22  21   20  19  10  9   8   7   6   5  4   3      0
+ * +---+---+---+---+------+----+----+------+---+---+---+---+---+------------+
+ * | N | Z | C | V | RES0 | SS | IL | RES0 | D | A | I | F | 0 | 0 | M[3:0] |
+ * +---+---+---+---+------+----+----+------+---+---+---+---+---+------------+
+ *
+ * AArch32 -> AArch64 Exception
+ * (see also ARMv7-AR ARM B1.3.3 CSPR/SPSR formats)
+ *  31  30  29  28  27  26     25 24  23  22  21   20  19     16
+ * +---+---+---+---+---+---------+---+------+----+----+---------+
+ * | N | Z | C | V | Q | IT[1:0] | J | RES0 | SS | IL | GE[3:0] |
+ * +---+---+---+---+---+---------+---+------+----+----+---------+
+ *  15     10  9   8   7   6   5   4  3      0
+ * +---------+---+---+---+---+---+---+--------+
+ * | IT[7:2] | E | A | I | F | T | 1 | M[3:0] |
+ * +---------+---+---+---+---+---+---+--------+
+ *
+ * M[4] = nRW - 0 = 64bit, 1 = 32bit
+ * Bit definitions for ARMv8 SPSR (PSTATE) format.
+ * Only these are valid when in AArch64 mode; in
+ * AArch32 mode SPSRs are basically CPSR-format.
+ *
+ * Also ARMv7-M ARM B1.4.2, special purpose program status register xPSR
+ */
+
+/* Save the program state */
+static inline uint32_t save_state_to_spsr(CPUARMState *env)
+{
+    uint32_t final_spsr = 0;
+
+    /* Calculate integer flags */
+    final_spsr |= (env->NF & 0x80000000) ? PSTATE_N : 0; /* bit 31 */
+    final_spsr |= (env->ZF == 0) ? PSTATE_Z : 0;
+    final_spsr |= env->CF ? PSTATE_C : 0;                /* or env->CF << 29 */
+    final_spsr |= (env->VF & 0x80000000) ? PSTATE_V : 0; /* bit 31 */
+
+    if (is_a64(env)) {
+        /* SS - Software Step */
+        /* IL - Illegal execution state */
+        /* DAIF flags - should we mask?*/
+        final_spsr |= (env->daif & PSTATE_DAIF);
+        /* And the final un-cached bits */
+        final_spsr |= (env->pstate & ~AARCH64_CACHED_PSTATE_BITS);
+    } else {
+        /* condexec_bits is split over two parts */
+        final_spsr |= ((env->condexec_bits & 3) << 25);
+        final_spsr |= ((env->condexec_bits & 0xfc) << 8);
+
+        if (arm_feature(env, ARM_FEATURE_M)) {
+            final_spsr |= (env->thumb << 24);   /* alt pos */
+            final_spsr |= env->v7m.exception;
+        } else {
+            final_spsr |= env->QF ? PSTATE_Q : 0;
+            /* GE needs shifting into place */
+            final_spsr |= (env->GE << 16);
+            /* AIF is a a subset of DAIF */
+            final_spsr |= (env->daif & PSTATE_AIF);
+            final_spsr |= env->thumb ? PSTATE_T : 0;
+
+            final_spsr |= PSTATE_nRW;
+
+            /* And the final un-cached bits */
+            final_spsr |= (env->uncached_cpsr & ~AARCH32_CACHED_PSTATE_BITS);
+        }
+    }
+    return final_spsr;
+}
+
+/* Restore the program state.
+ *
+ * This restores the program execution state including it's current
+ * execution mode. However validation of mode changes and additional
+ * registers and state that need changing should be done by the
+ * calling function.
+ *
+ * The simple set_condition_codes() function can be used just to
+ * update the cached integer flags which are quite often manipulated
+ * alone.
+ */
+
+/* Only update the cached condition codes. */
+static inline void set_condition_codes(CPUARMState *env, uint32_t new_flags)
+{
+    /* Process the integer flags directly */
+    env->ZF = (~new_flags) & CPSR_Z;
+    env->NF = new_flags;
+    env->CF = (new_flags >> 29) & 1;
+    env->VF = (new_flags << 3) & 0x80000000;
+}
+
+/* Restore the complete program state */
+static inline void restore_state_from_spsr(CPUARMState *env,
+                                           uint32_t saved_state)
+{
+    set_condition_codes(env, saved_state);
+
+    /* the rest depends on the mode we end up in */
+    env->aarch64 = (saved_state & PSTATE_nRW) ? 0 : 1;
+
+    if (is_a64(env)) {
+        env->daif = saved_state & PSTATE_DAIF;
+        env->pstate = (saved_state & ~AARCH64_CACHED_PSTATE_BITS);
+    } else {
+        if (arm_feature(env, ARM_FEATURE_M)) {
+            fprintf(stderr, "%s: M state not yet implmented\n", __func__);
+        } else {
+            env->QF = saved_state & PSTATE_Q ? 1 : 0;
+            /* condexec_bits is split over two parts */
+            env->condexec_bits = (saved_state & CPSR_IT_0_1) >> 25;
+            env->condexec_bits |= (saved_state & CPSR_IT_2_7) >> 8;
+
+            /* GE needs shifting into place */
+            env->GE = (saved_state >> 16) & 0xf;
+
+            /* AIF is a a subset of DAIF */
+            env->daif = (saved_state & PSTATE_AIF);
+
+            env->thumb = saved_state & PSTATE_T ? 1 : 0;
+
+            /* And the final un-cached bits */
+            env->uncached_cpsr = saved_state & ~AARCH32_CACHED_PSTATE_BITS;
+        }
+    }
+}
+
+
 void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 
 /* Interface between CPU and Interrupt controller.  */