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.
--- WIP notes: - From this I'll look at - cpsr_read/cpsr_write - pstate_read/pstate_write - xpsr_read/xpsr_write - direct access to env->uncached_cpsr - direct access to env->pstate diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 5e6df38..9e41f82 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -430,26 +430,27 @@ int arm_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw, /* Execution state bits. MRS read as zero, MSR writes ignored. */ #define CPSR_EXEC (CPSR_T | CPSR_IT | CPSR_J) -/* Bit definitions for ARMv8 SPSR (PSTATE) format. - * Only these are valid when in AArch64 mode; in - * AArch32 mode SPSRs are basically CPSR-format. - */ + #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 @@ -492,7 +493,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 @@ -681,6 +682,122 @@ 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. + */ + +/* 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 + + /* will the compiler do better with the original? + int ZF; + ZF = (env->ZF == 0); + nzcv = (env->NF & 0x80000000) + | (ZF << 30) + | (env->CF << 29) + | ((env->VF & 0x80000000) >> 3); + */ + + 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 { + if (arm_feature(env, ARM_FEATURE_M)) { + fprintf(stderr,"%s: M state not yet implmented\n", __func__); + } else { + final_spsr |= env->QF ? PSTATE_Q : 0; + /* condexec_bits is split over two parts */ + final_spsr |= ((env->condexec_bits & 3) << 25); + final_spsr |= ((env->condexec_bits & 0xfc) << 8); + /* 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; +} + +static inline void restore_state_from_spsr(CPUARMState *env, uint32_t saved_state) +{ + /* Process the integer flags directly */ + env->ZF = (~saved_state) & CPSR_Z; + env->NF = saved_state; + env->CF = (saved_state >> 29) & 1; + env->VF = (saved_state << 3) & 0x80000000; + + /* 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. */ -- 2.0.0