From cddd64fd30987a1dde018d0e80ec8af137d9e27e Mon Sep 17 00:00:00 2001 From: qiaowei Date: Wed, 13 May 2020 15:16:45 +0800 Subject: [PATCH] armv8-m: Add stack overflow by stack pointer limit register Signed-off-by: qiaowei Change-Id: I0f0ae0fb8edb8e1690b3c5e3e8b3189d51a318b0 --- arch/arm/include/armv8-m/irq_cmnvector.h | 8 ++++- arch/arm/include/armv8-m/irq_lazyfpu.h | 8 ++++- arch/arm/src/armv8-m/Kconfig | 28 +++++++++++++--- arch/arm/src/armv8-m/arm_exception.S | 42 +++++++++++++++++++++--- arch/arm/src/armv8-m/arm_initialstate.c | 6 ++++ arch/arm/src/armv8-m/arm_lazyexception.S | 41 ++++++++++++++++++++--- 6 files changed, 118 insertions(+), 15 deletions(-) diff --git a/arch/arm/include/armv8-m/irq_cmnvector.h b/arch/arm/include/armv8-m/irq_cmnvector.h index 24b02b3c9ac..4c784e70e0c 100644 --- a/arch/arm/include/armv8-m/irq_cmnvector.h +++ b/arch/arm/include/armv8-m/irq_cmnvector.h @@ -82,7 +82,13 @@ /* The total number of registers saved by software */ -#define SW_XCPT_REGS (SW_INT_REGS + SW_FPU_REGS) +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE +# define REG_SPLIM (SW_INT_REGS + SW_FPU_REGS + 0) /* REG_SPLIM */ +# define SW_XCPT_REGS (SW_INT_REGS + SW_FPU_REGS + 1) +#else +# define SW_XCPT_REGS (SW_INT_REGS + SW_FPU_REGS) +#endif + #define SW_XCPT_SIZE (4 * SW_XCPT_REGS) /* On entry into an IRQ, the hardware automatically saves the following diff --git a/arch/arm/include/armv8-m/irq_lazyfpu.h b/arch/arm/include/armv8-m/irq_lazyfpu.h index 88c5e03936d..33af6d81e06 100644 --- a/arch/arm/include/armv8-m/irq_lazyfpu.h +++ b/arch/arm/include/armv8-m/irq_lazyfpu.h @@ -129,7 +129,13 @@ /* The total number of registers saved by software */ -#define SW_XCPT_REGS (SW_INT_REGS + SW_FPU_REGS) +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE +# define REG_SPLIM (SW_INT_REGS + SW_FPU_REGS + 0) /* REG_SPLIM */ +# define SW_XCPT_REGS (SW_INT_REGS + SW_FPU_REGS + 1) +#else +# define SW_XCPT_REGS (SW_INT_REGS + SW_FPU_REGS) +#endif + #define SW_XCPT_SIZE (4 * SW_XCPT_REGS) /* On entry into an IRQ, the hardware automatically saves the following diff --git a/arch/arm/src/armv8-m/Kconfig b/arch/arm/src/armv8-m/Kconfig index 991f7400495..016d8d42415 100644 --- a/arch/arm/src/armv8-m/Kconfig +++ b/arch/arm/src/armv8-m/Kconfig @@ -155,14 +155,15 @@ config ARMV8M_TARGET2_PREL ---help--- Perform a PC relative relocation for relocation type R_ARM_TARGET2 -config ARMV8M_HAVE_STACKCHECK - bool - default n +choice + prompt "Select the stack protection Schema" + default ARMV8M_STACKCHECK_NONE + +config ARMV8M_STACKCHECK_NONE + bool "Do not check for stack overflow" config ARMV8M_STACKCHECK bool "Check for stack overflow on each function call" - default n - depends on ARMV8M_HAVE_STACKCHECK ---help--- This check uses R10 to check for a stack overflow within each function call. This has performances and code size impacts, but it @@ -177,6 +178,23 @@ config ARMV8M_STACKCHECK compile. This addition to your CFLAGS should probably be added to the definition of the CFFLAGS in your board Make.defs file. +config ARMV8M_STACKCHECK_HARDWARE + bool "Check for stack overflow by stack pointer limit register" + ---help--- + This option signifies the CPU has the MSPLIM, PSPLIM registers. + + The stack pointer limit registers, MSPLIM, PSPLIM, limit the + extend to which the Main and Process Stack Pointers, respectively, + can descend. MSPLIM, PSPLIM are always present in ARMv8-M + MCUs that implement the ARMv8-M Main Extension (Mainline). + + In an ARMv8-M Mainline implementation with the Security Extension + the MSPLIM, PSPLIM registers have additional Secure instances. + In an ARMv8-M Baseline implementation with the Security Extension + the MSPLIM, PSPLIM registers have only Secure instances. + +endchoice + config ARMV8M_ITMSYSLOG bool "ITM SYSLOG support" default n diff --git a/arch/arm/src/armv8-m/arm_exception.S b/arch/arm/src/armv8-m/arm_exception.S index 85951b5e6f8..c7dc5af6e09 100644 --- a/arch/arm/src/armv8-m/arm_exception.S +++ b/arch/arm/src/armv8-m/arm_exception.S @@ -105,6 +105,10 @@ #if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7 .macro setintstack, tmp1, tmp2 +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + ldr \tmp1, =g_intstackalloc + msr msplim, \tmp1 +#endif ldr sp, =g_intstackbase .endm #endif @@ -148,12 +152,23 @@ exception_common: tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */ beq 1f /* Branch if context already on the MSP */ mrs r1, psp /* R1=The process stack pointer (PSP) */ - mov sp, r1 /* Set the MSP to the PSP */ - + mov sp, r1 /* Set the MSP to the PSP */ 1: mov r2, sp /* R2=Copy of the main/process stack pointer */ add r2, #HW_XCPT_SIZE /* R2=MSP/PSP before the interrupt was taken */ /* (ignoring the xPSR[9] alignment bit) */ +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + mov r3, #0x0 + + ittee eq + mrseq r1, msplim + msreq msplim, r3 + mrsne r1, psplim + msrne psplim, r3 + + stmdb sp!, {r1} +#endif + #ifdef CONFIG_ARMV8M_USEBASEPRI mrs r3, basepri /* R3=Current BASEPRI setting */ #else @@ -249,7 +264,11 @@ exception_common: stmdb r1!, {r4-r11} /* Store eight registers on the return stack */ ldmia r0!, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */ #ifdef CONFIG_ARCH_FPU - vldmia r0, {s16-s31} /* Recover S16-S31 */ + vldmia r0!, {s16-s31} /* Recover S16-S31 */ +#endif + +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + ldmia r0, {r0} /* Get psplim/msplim*/ #endif b 3f /* Re-join common logic */ @@ -261,7 +280,11 @@ exception_common: ldmia r1!, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */ #ifdef CONFIG_ARCH_FPU - vldmia r1!, {s16-s31} /* Recover S16-S31 */ + vldmia r1!, {s16-s31} /* Recover S16-S31 */ +#endif + +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + ldmia r1!, {r0} /* Get psplim/msplim */ #endif 3: @@ -279,15 +302,26 @@ exception_common: beq 4f /* Branch if privileged */ orr r2, r2, #1 /* Unprivileged mode */ +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + msr psplim, r0 +#endif msr psp, r1 /* R1=The process stack pointer */ b 5f 4: bic r2, r2, #1 /* Privileged mode */ +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + msr msplim, r0 +#endif msr msp, r1 /* R1=The main stack pointer */ 5: msr control, r2 /* Save the updated control register */ #else tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */ +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + ite eq + msreq msplim, r0 + msrne psplim, r0 +#endif ite eq /* next two instructions conditional */ msreq msp, r1 /* R1=The main stack pointer */ msrne psp, r1 /* R1=The process stack pointer */ diff --git a/arch/arm/src/armv8-m/arm_initialstate.c b/arch/arm/src/armv8-m/arm_initialstate.c index ad6751ff02d..969c9bec32c 100644 --- a/arch/arm/src/armv8-m/arm_initialstate.c +++ b/arch/arm/src/armv8-m/arm_initialstate.c @@ -73,6 +73,12 @@ void up_initial_state(struct tcb_s *tcb) xcp->regs[REG_R10] = (uint32_t)tcb->stack_alloc_ptr + 64; #endif +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + /* Save the stack limit value, will be used in context switch. */ + + xcp->regs[REG_SPLIM] = (uint32_t)tcb->stack_alloc_ptr; +#endif + /* Save the task entry point (stripping off the thumb bit) */ xcp->regs[REG_PC] = (uint32_t)tcb->start & ~1; diff --git a/arch/arm/src/armv8-m/arm_lazyexception.S b/arch/arm/src/armv8-m/arm_lazyexception.S index 2bb1093b46f..ade51c1adba 100644 --- a/arch/arm/src/armv8-m/arm_lazyexception.S +++ b/arch/arm/src/armv8-m/arm_lazyexception.S @@ -88,6 +88,10 @@ #if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7 .macro setintstack, tmp1, tmp2 +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + ldr \tmp1, =g_intstackalloc + msr msplim, \tmp1 +#endif ldr sp, =g_intstackbase .endm #endif @@ -125,16 +129,17 @@ exception_common: /* Complete the context save */ + tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */ + #ifdef CONFIG_BUILD_PROTECTED /* The EXC_RETURN value will be 0xfffffff9 (privileged thread) or 0xfffffff1 * (handler mode) if the stack is on the MSP. It can only be on the PSP if * EXC_RETURN is 0xfffffffd (unprivileged thread) */ - tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */ beq 1f /* Branch if context already on the MSP */ mrs r1, psp /* R1=The process stack pointer (PSP) */ - mov sp, r1 /* Set the MSP to the PSP */ + mov sp, r1 /* Set the MSP to the PSP */ 1: #endif @@ -147,6 +152,18 @@ exception_common: mov r2, sp /* R2=Copy of the main/process stack pointer */ add r2, #HW_XCPT_SIZE /* R2=MSP/PSP before the interrupt was taken */ +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + mov r3, #0x0 + + ittee eq + mrseq r1, msplim + msreq msplim, r3 + mrsne r1, psplim + msrne psplim, r3 + + stmdb sp!, {r1} +#endif + #ifdef CONFIG_ARMV8M_USEBASEPRI mrs r3, basepri /* R3=Current BASEPRI setting */ #else @@ -246,9 +263,12 @@ exception_common: ldr r1, [r0, #(4*REG_SP)] /* R1=Value of SP before interrupt */ stmdb r1!, {r4-r11} /* Store eight registers in HW save area */ #ifdef CONFIG_BUILD_PROTECTED - ldmia r0, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */ + ldmia r0!, {r2-r11,r14} /* Recover R4-R11, r14 + 2 temp values */ #else - ldmia r0, {r2-r11} /* Recover R4-R11 + 2 temp values */ + ldmia r0!, {r2-r11} /* Recover R4-R11 + 2 temp values */ +#endif +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + ldmia r0, {r0} /* Get psplim/msplim*/ #endif b 3f /* Re-join common logic */ @@ -274,6 +294,10 @@ exception_common: add r1, #(4*SW_FPU_REGS) #endif +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + ldmia r1!, {r0} /* Get psplim/msplim */ +#endif + /* Set up to return from the exception * * Here: @@ -296,14 +320,23 @@ exception_common: beq 4f /* Branch if privileged */ orr r2, r2, #1 /* Unprivileged mode */ +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + msr psplim, r0 +#endif msr psp, r1 /* R1=The process stack pointer */ b 5f 4: bic r2, r2, #1 /* Privileged mode */ +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + msr msplim, r0 +#endif msr msp, r1 /* R1=The main stack pointer */ 5: msr control, r2 /* Save the updated control register */ #else +#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE + msr msplim, r0 +#endif msr msp, r1 /* Recover the return MSP value */ /* Preload r14 with the special return value first (so that the return