target/arm: Set FPCCR.S when executing M-profile floating point insns

The M-profile FPCCR.S bit indicates the security status of
the floating point context. In the pseudocode ExecuteFPCheck()
function it is unconditionally set to match the current
security state whenever a floating point instruction is
executed.

Implement this by adding a new TB flag which tracks whether
FPCCR.S is different from the current security state, so
that we only need to emit the code to update it in the
less-common case when it is not already set correctly.

Note that we will add the handling for the other work done
by ExecuteFPCheck() in later commits.

Backports commit 6d60c67a1a03be32c3342aff6604cdc5095088d1 from qemu
This commit is contained in:
Peter Maydell 2019-04-30 10:47:32 -04:00 committed by Lioncash
parent 8d726490ff
commit 87c8c0fde7
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
4 changed files with 28 additions and 0 deletions

View file

@ -3110,6 +3110,8 @@ FIELD(TBFLAG_A32, NS, 6, 1)
FIELD(TBFLAG_A32, VFPEN, 7, 1) FIELD(TBFLAG_A32, VFPEN, 7, 1)
FIELD(TBFLAG_A32, CONDEXEC, 8, 8) FIELD(TBFLAG_A32, CONDEXEC, 8, 8)
FIELD(TBFLAG_A32, SCTLR_B, 16, 1) FIELD(TBFLAG_A32, SCTLR_B, 16, 1)
/* For M profile only, set if FPCCR.S does not match current security state */
FIELD(TBFLAG_A32, FPCCR_S_WRONG, 20, 1)
/* For M profile only, Handler (ie not Thread) mode */ /* For M profile only, Handler (ie not Thread) mode */
FIELD(TBFLAG_A32, HANDLER, 21, 1) FIELD(TBFLAG_A32, HANDLER, 21, 1)
/* For M profile only, whether we should generate stack-limit checks */ /* For M profile only, whether we should generate stack-limit checks */

View file

@ -13213,6 +13213,11 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
flags = FIELD_DP32(flags, TBFLAG_A32, STACKCHECK, 1); flags = FIELD_DP32(flags, TBFLAG_A32, STACKCHECK, 1);
} }
if (arm_feature(env, ARM_FEATURE_M_SECURITY) &&
FIELD_EX32(env->v7m.fpccr[M_REG_S], V7M_FPCCR, S) != env->v7m.secure) {
flags = FIELD_DP32(flags, TBFLAG_A32, FPCCR_S_WRONG, 1);
}
*pflags = flags; *pflags = flags;
*cs_base = 0; *cs_base = 0;
} }

View file

@ -3528,6 +3528,25 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
} }
} }
if (arm_dc_feature(s, ARM_FEATURE_M)) {
/* Handle M-profile lazy FP state mechanics */
/* Update ownership of FP context: set FPCCR.S to match current state */
if (s->v8m_fpccr_s_wrong) {
TCGv_i32 tmp;
tmp = load_cpu_field(s->uc, v7m.fpccr[M_REG_S]);
if (s->v8m_secure) {
tcg_gen_ori_i32(tcg_ctx, tmp, tmp, R_V7M_FPCCR_S_MASK);
} else {
tcg_gen_andi_i32(tcg_ctx, tmp, tmp, ~R_V7M_FPCCR_S_MASK);
}
store_cpu_field(s, tmp, v7m.fpccr[M_REG_S]);
/* Don't need to do this for any further FP insns in this TB */
s->v8m_fpccr_s_wrong = false;
}
}
if (extract32(insn, 28, 4) == 0xf) { if (extract32(insn, 28, 4) == 0xf) {
/* /*
* Encodings with T=1 (Thumb) or unconditional (ARM): * Encodings with T=1 (Thumb) or unconditional (ARM):
@ -13520,6 +13539,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
dc->v8m_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) && dc->v8m_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&
regime_is_secure(env, dc->mmu_idx); regime_is_secure(env, dc->mmu_idx);
dc->v8m_stackcheck = FIELD_EX32(tb_flags, TBFLAG_A32, STACKCHECK); dc->v8m_stackcheck = FIELD_EX32(tb_flags, TBFLAG_A32, STACKCHECK);
dc->v8m_fpccr_s_wrong = FIELD_EX32(tb_flags, TBFLAG_A32, FPCCR_S_WRONG);
dc->cp_regs = cpu->cp_regs; dc->cp_regs = cpu->cp_regs;
dc->features = env->features; dc->features = env->features;

View file

@ -39,6 +39,7 @@ typedef struct DisasContext {
bool v7m_handler_mode; bool v7m_handler_mode;
bool v8m_secure; /* true if v8M and we're in Secure mode */ bool v8m_secure; /* true if v8M and we're in Secure mode */
bool v8m_stackcheck; /* true if we need to perform v8M stack limit checks */ bool v8m_stackcheck; /* true if we need to perform v8M stack limit checks */
bool v8m_fpccr_s_wrong; /* true if v8M FPCCR.S != v8m_secure */
/* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI /* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI
* so that top level loop can generate correct syndrome information. * so that top level loop can generate correct syndrome information.
*/ */