armv8-m: Add stack overflow by stack pointer limit register

Signed-off-by: qiaowei <qiaowei@xiaomi.com>
Change-Id: I0f0ae0fb8edb8e1690b3c5e3e8b3189d51a318b0
This commit is contained in:
qiaowei 2020-05-13 15:16:45 +08:00 committed by patacongo
parent 57bc329aac
commit cddd64fd30
6 changed files with 118 additions and 15 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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;

View file

@ -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