From 8b3b54896140cd878c8d39fc8b32db5d0e2c9629 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 8 Oct 2018 13:46:38 -0400 Subject: [PATCH] target/arm: Define new TBFLAG for v8M stack checking The Arm v8M architecture includes hardware stack limit checking. When certain instructions update the stack pointer, if the new value of SP is below the limit set in the associated limit register then an exception is taken. Add a TB flag that tracks whether the limit-checking code needs to be emitted. Backports commit 4730fb85035e99c909db7d14ef76cd17f28f4423 from qemu --- qemu/target/arm/cpu.h | 7 +++++++ qemu/target/arm/helper.c | 10 ++++++++++ qemu/target/arm/translate.c | 1 + qemu/target/arm/translate.h | 1 + 4 files changed, 19 insertions(+) diff --git a/qemu/target/arm/cpu.h b/qemu/target/arm/cpu.h index 05bbc5dc..279738af 100644 --- a/qemu/target/arm/cpu.h +++ b/qemu/target/arm/cpu.h @@ -1288,8 +1288,10 @@ FIELD(V7M_CCR, UNALIGN_TRP, 3, 1) FIELD(V7M_CCR, DIV_0_TRP, 4, 1) FIELD(V7M_CCR, BFHFNMIGN, 8, 1) FIELD(V7M_CCR, STKALIGN, 9, 1) +FIELD(V7M_CCR, STKOFHFNMIGN, 10, 1) FIELD(V7M_CCR, DC, 16, 1) FIELD(V7M_CCR, IC, 17, 1) +FIELD(V7M_CCR, BP, 18, 1) /* V7M SCR bits */ FIELD(V7M_SCR, SLEEPONEXIT, 1, 1) @@ -2752,6 +2754,9 @@ static inline bool arm_singlestep_active(CPUARMState *env) /* For M profile only, Handler (ie not Thread) mode */ #define ARM_TBFLAG_HANDLER_SHIFT 21 #define ARM_TBFLAG_HANDLER_MASK (1 << ARM_TBFLAG_HANDLER_SHIFT) +/* For M profile only, whether we should generate stack-limit checks */ +#define ARM_TBFLAG_STACKCHECK_SHIFT 22 +#define ARM_TBFLAG_STACKCHECK_MASK (1 << ARM_TBFLAG_STACKCHECK_SHIFT) /* Bit usage when in AArch64 state */ #define ARM_TBFLAG_TBI0_SHIFT 0 /* TBI0 for EL0/1 or TBI for EL2/3 */ @@ -2794,6 +2799,8 @@ static inline bool arm_singlestep_active(CPUARMState *env) (((F) & ARM_TBFLAG_BE_DATA_MASK) >> ARM_TBFLAG_BE_DATA_SHIFT) #define ARM_TBFLAG_HANDLER(F) \ (((F) & ARM_TBFLAG_HANDLER_MASK) >> ARM_TBFLAG_HANDLER_SHIFT) +#define ARM_TBFLAG_STACKCHECK(F) \ + (((F) & ARM_TBFLAG_STACKCHECK_MASK) >> ARM_TBFLAG_STACKCHECK_SHIFT) #define ARM_TBFLAG_TBI0(F) \ (((F) & ARM_TBFLAG_TBI0_MASK) >> ARM_TBFLAG_TBI0_SHIFT) #define ARM_TBFLAG_TBI1(F) \ diff --git a/qemu/target/arm/helper.c b/qemu/target/arm/helper.c index 7c716b3d..f4f68d74 100644 --- a/qemu/target/arm/helper.c +++ b/qemu/target/arm/helper.c @@ -11916,6 +11916,16 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, flags |= ARM_TBFLAG_HANDLER_MASK; } + /* v8M always applies stack limit checks unless CCR.STKOFHFNMIGN is + * suppressing them because the requested execution priority is less than 0. + */ + if (arm_feature(env, ARM_FEATURE_V8) && + arm_feature(env, ARM_FEATURE_M) && + !((mmu_idx & ARM_MMU_IDX_M_NEGPRI) && + (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKOFHFNMIGN_MASK))) { + flags |= ARM_TBFLAG_STACKCHECK_MASK; + } + *pflags = flags; *cs_base = 0; } diff --git a/qemu/target/arm/translate.c b/qemu/target/arm/translate.c index 34bfb0aa..d32d62eb 100644 --- a/qemu/target/arm/translate.c +++ b/qemu/target/arm/translate.c @@ -12666,6 +12666,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(dc->base.tb->flags); dc->v8m_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) && regime_is_secure(env, dc->mmu_idx); + dc->v8m_stackcheck = ARM_TBFLAG_STACKCHECK(dc->base.tb->flags); dc->cp_regs = cpu->cp_regs; dc->features = env->features; diff --git a/qemu/target/arm/translate.h b/qemu/target/arm/translate.h index d857d315..4634b73b 100644 --- a/qemu/target/arm/translate.h +++ b/qemu/target/arm/translate.h @@ -37,6 +37,7 @@ typedef struct DisasContext { int vec_stride; bool v7m_handler_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 */ /* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI * so that top level loop can generate correct syndrome information. */