bits when modifying CPSR. Signed-off-by: Fabian Aggeler <aggel...@ethz.ch> --- target-arm/cpu.h | 2 ++ target-arm/helper.c | 41 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 212cb64..5de0c77 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -675,6 +675,8 @@ static inline int arm_feature(CPUARMState *env, int feature) #define SCR_NS (1U << 0) #define SCR_IRQ (1U << 1) #define SCR_FIQ (1U << 2) +#define SCR_FW (1U << 4) +#define SCR_AW (1U << 5) /* Return true if the processor is in secure state */ static inline bool arm_is_secure(CPUARMState *env) diff --git a/target-arm/helper.c b/target-arm/helper.c index a5ba480..7151325 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3169,9 +3169,6 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) env->GE = (val >> 16) & 0xf; } - env->daif &= ~(CPSR_AIF & mask); - env->daif |= val & CPSR_AIF & mask; - if ((env->uncached_cpsr ^ val) & mask & CPSR_M) { if (bad_mode_switch(env, val & CPSR_M)) { /* Attempt to switch to an invalid mode: this is UNPREDICTABLE. @@ -3183,6 +3180,44 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) switch_mode(env, val & CPSR_M); } } + + /* In an implementation that does not include Virtualization Extensions + * the SCR.FW and SCR.AW bit control whether non-secure software is allowed + * to change the CPSR_F and CPSR_A bits respectively. + */ + if ((mask & CPSR_A) + && (val & CPSR_A) != (env->uncached_cpsr & CPSR_A) + && arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS) + && !(env->cp15.c1_scr & SCR_AW) && !arm_is_secure(env)) { + qemu_log_mask(LOG_GUEST_ERROR, "Ignoring attempt to switch CPSR_A " + "flag from non-secure world with SCR.AW bit set\n"); + mask &= ~CPSR_A; + } + + if ((mask & CPSR_F)) { + + /* Check whether non-maskable FIQ (NMFI) support is enabled. + * If this bit is set software is not allowed to mask FIQs, + * but is allowed to set CPSR_F to 0. + */ + if ((arm_current_sctlr(env) & SCTLR_NMFI) && (val & CPSR_F)) { + qemu_log_mask(LOG_GUEST_ERROR, "Ignoring attempt to enable CPSR_F " + "flag (non-maskable FIQ [NMFI] support enabled)\n"); + mask &= ~CPSR_F; + } + + if ((val & CPSR_F) != (env->uncached_cpsr & CPSR_F) + && arm_feature(env, ARM_FEATURE_SECURITY_EXTENSIONS) + && !(env->cp15.c1_scr & SCR_FW) && !arm_is_secure(env)) { + qemu_log_mask(LOG_GUEST_ERROR, "Ignoring attempt to switch CPSR_F " + "flag from non-secure world with SCR.FW bit set\n"); + mask &= ~CPSR_F; + } + } + + env->daif &= ~(CPSR_AIF & mask); + env->daif |= val & CPSR_AIF & mask; + mask &= ~CACHED_CPSR_BITS; env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask); } -- 1.8.3.2