arc: implement stack checking
ARC CPU has stack checking feature that allows to trigger an exception whenever the stack is incorrectly accessed. This patch implements the stack_top and stack_base register updates on context switches, and activates the Stack Checking bit of STATUS32 register when the CPU is in the context of a fiber or task. As GCC accesses the non-yet allocated stack with frame pointer enabled, this patch also add the omit-frame-pointer gcc flag in order to work properly. Change-Id: Ia9e224085a03bd29d682fb8f51f8e712f2ccb556 Signed-off-by: Alexandre d'Alton <alexandre.dalton@intel.com>
This commit is contained in:
parent
c65821718f
commit
f91e55b798
9 changed files with 77 additions and 5 deletions
|
@ -130,6 +130,14 @@ config FIRQ_STACK_SIZE
|
|||
FIRQs and regular IRQs have different stacks so that a FIRQ can start
|
||||
running without doing stack switching in software.
|
||||
|
||||
config ARC_STACK_CHECKING
|
||||
bool "Enable Stack Checking"
|
||||
depends on CPU_ARCV2
|
||||
default n
|
||||
help
|
||||
ARCV2 has a special feature allowing to check stack overflows. This
|
||||
enables code that allows using this debug feature
|
||||
|
||||
config FAULT_DUMP
|
||||
int
|
||||
prompt "Fault dump level"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
cflags-y += $(call cc-option,-ffunction-sections,) $(call cc-option,-fdata-sections,)
|
||||
cflags-$(CONFIG_ARC_STACK_CHECKING) = $(call cc-option,-fomit-frame-pointer)
|
||||
cflags-$(CONFIG_LTO) = $(call cc-option,-flto,)
|
||||
|
||||
include $(srctree)/arch/$(ARCH)/soc/$(SOC_NAME)/Makefile
|
||||
|
|
|
@ -48,8 +48,8 @@ SECTION_VAR(NOINIT, _firq_stack)
|
|||
* LP_COUNT/LP_END registers, which are not banked.
|
||||
*
|
||||
* If all FIRQ ISRs are programmed such that there are no use of the LP
|
||||
* registers (ie. no LPcc instruction), then the kernel can be configured to
|
||||
* remove the use of _firq_enter().
|
||||
* registers (ie. no LPcc instruction), and CONFIG_ARC_STACK_CHECKING is
|
||||
* not set, then the kernel can be configured to remove the use of _firq_enter().
|
||||
*
|
||||
* When entering a FIRQ, interrupts might as well be locked: the processor is
|
||||
* running at its highest priority, and cannot be preempted by anything.
|
||||
|
@ -61,6 +61,13 @@ SECTION_VAR(NOINIT, _firq_stack)
|
|||
|
||||
SECTION_FUNC(TEXT, _firq_enter)
|
||||
|
||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||
/* disable stack checking */
|
||||
lr r2, [_ARC_V2_STATUS32]
|
||||
bclr r2, r2, _ARC_V2_STATUS32_SC_BIT
|
||||
kflag r2
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_FIRQ_NO_LPCC
|
||||
/*
|
||||
* Unlike the rest of context switching code, r2 is loaded with something
|
||||
|
@ -184,6 +191,13 @@ _firq_reschedule:
|
|||
ld r3, [r2, __tTCS_link_OFFSET]
|
||||
st r3, [r1, __tNANO_fiber_OFFSET]
|
||||
|
||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||
/* Use stack top and down registers from restored context */
|
||||
add r3, r2, __tTCS_NOFLOAT_SIZEOF
|
||||
sr r3, [_ARC_V2_KSTACK_TOP]
|
||||
ld r3, [r2, __tTCS_stack_top_OFFSET]
|
||||
sr r3, [_ARC_V2_KSTACK_BASE]
|
||||
#endif
|
||||
/*
|
||||
* _load_callee_saved_regs expects incoming thread in r2.
|
||||
* _load_callee_saved_regs restores the stack pointer.
|
||||
|
|
|
@ -48,6 +48,9 @@ GEN_OFFSET_SYM(tNANO, idle);
|
|||
GEN_OFFSET_SYM(tTCS, intlock_key);
|
||||
GEN_OFFSET_SYM(tTCS, relinquish_cause);
|
||||
GEN_OFFSET_SYM(tTCS, return_value);
|
||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||
GEN_OFFSET_SYM(tTCS, stack_top);
|
||||
#endif
|
||||
#ifdef CONFIG_THREAD_CUSTOM_DATA
|
||||
GEN_OFFSET_SYM(tTCS, custom_data);
|
||||
#endif
|
||||
|
|
|
@ -51,6 +51,12 @@ GTEXT(_rirq_exit)
|
|||
SECTION_FUNC(TEXT, _rirq_enter)
|
||||
|
||||
mov r1, _nanokernel
|
||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||
/* disable stack checking */
|
||||
lr r2, [_ARC_V2_STATUS32]
|
||||
bclr r2, r2, _ARC_V2_STATUS32_SC_BIT
|
||||
kflag r2
|
||||
#endif
|
||||
ld r2, [r1, __tNANO_current_OFFSET]
|
||||
#if CONFIG_NUM_REGULAR_IRQ_PRIO_LEVELS == 1
|
||||
st sp, [r2, __tTCS_preempReg_OFFSET + __tPreempt_sp_OFFSET]
|
||||
|
@ -126,6 +132,13 @@ _rirq_reschedule:
|
|||
ld r3, [r2, __tTCS_link_OFFSET]
|
||||
st r3, [r1, __tNANO_fiber_OFFSET]
|
||||
|
||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||
/* Use stack top and down registers from restored context */
|
||||
add r3, r2, __tTCS_NOFLOAT_SIZEOF
|
||||
sr r3, [_ARC_V2_KSTACK_TOP]
|
||||
ld r3, [r2, __tTCS_stack_top_OFFSET]
|
||||
sr r3, [_ARC_V2_KSTACK_BASE]
|
||||
#endif
|
||||
/*
|
||||
* _load_callee_saved_regs expects incoming thread in r2.
|
||||
* _load_callee_saved_regs restores the stack pointer.
|
||||
|
|
|
@ -86,6 +86,11 @@ SECTION_FUNC(TEXT, _Swap)
|
|||
*/
|
||||
lr r3, [_ARC_V2_STATUS32]
|
||||
push_s r3
|
||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||
/* disable stack checking during swap */
|
||||
bclr r3, r3, _ARC_V2_STATUS32_SC_BIT
|
||||
kflag r3
|
||||
#endif
|
||||
push_s blink
|
||||
|
||||
_save_callee_saved_regs
|
||||
|
@ -118,7 +123,13 @@ _finish_swapping_to_thread:
|
|||
ld r3, [r2, __tTCS_flags_OFFSET]
|
||||
st r3, [r1, __tNANO_flags_OFFSET]
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||
/* Use stack top and down registers from restored context */
|
||||
add r3, r2, __tTCS_NOFLOAT_SIZEOF
|
||||
sr r3, [_ARC_V2_KSTACK_TOP]
|
||||
ld r3, [r2, __tTCS_stack_top_OFFSET]
|
||||
sr r3, [_ARC_V2_KSTACK_BASE]
|
||||
#endif
|
||||
/* XXX - can be moved to delay slot of _CAUSE_RIRQ ? */
|
||||
st r2, [r1, __tNANO_current_OFFSET]
|
||||
|
||||
|
@ -168,11 +179,23 @@ _swap_return_from_firq:
|
|||
bbit1 ilink, _ARC_V2_STATUS32_AE_BIT, _return_from_exc
|
||||
|
||||
ld ilink, [sp, -4] /* status32 into ilink */
|
||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||
and ilink, ilink, 0x7fffbffe // keep SC off till we stop using under SP
|
||||
#else
|
||||
and ilink, ilink, 0x7ffffffe // keep interrupts disabled until seti
|
||||
#endif
|
||||
kflag ilink
|
||||
|
||||
ld ilink, [sp, -8] /* pc into ilink */
|
||||
|
||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||
/* Enable stack checking now it is safe */
|
||||
push_s r3
|
||||
lr r3, [_ARC_V2_STATUS32]
|
||||
bset r3, r3, _ARC_V2_STATUS32_SC_BIT
|
||||
flag r3
|
||||
pop_s r3
|
||||
#endif
|
||||
j.d [ilink]
|
||||
seti (_ARC_V2_DEF_IRQ_LEVEL | (1 << 4))
|
||||
|
||||
|
|
|
@ -131,8 +131,12 @@ void _new_thread(char *pStackMem, unsigned stackSize, _thread_entry_t pEntry,
|
|||
* enable the interrupts based on intlock_key
|
||||
* value.
|
||||
*/
|
||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||
pInitCtx->status32 = _ARC_V2_STATUS32_SC | _ARC_V2_STATUS32_E(_ARC_V2_DEF_IRQ_LEVEL);
|
||||
tcs->stack_top = (uint32_t) stackEnd;
|
||||
#else
|
||||
pInitCtx->status32 = _ARC_V2_STATUS32_E(_ARC_V2_DEF_IRQ_LEVEL);
|
||||
|
||||
#endif
|
||||
tcs->link = NULL;
|
||||
tcs->flags = priority == -1 ? TASK | PREEMPTIBLE : FIBER;
|
||||
tcs->prio = priority;
|
||||
|
|
|
@ -194,6 +194,9 @@ struct tcs {
|
|||
#ifdef CONFIG_ERRNO
|
||||
int errno_var;
|
||||
#endif
|
||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||
uint32_t stack_top;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct s_NANO {
|
||||
|
|
|
@ -46,6 +46,8 @@ extern "C" {
|
|||
#define _ARC_V2_IRQ_PRIO_PEND 0x200
|
||||
#define _ARC_V2_AUX_IRQ_HINT 0x201
|
||||
#define _ARC_V2_IRQ_PRIORITY 0x206
|
||||
#define _ARC_V2_KSTACK_TOP 0x264
|
||||
#define _ARC_V2_KSTACK_BASE 0x265
|
||||
#define _ARC_V2_ERET 0x400
|
||||
#define _ARC_V2_ERSTATUS 0x402
|
||||
#define _ARC_V2_ECR 0x403
|
||||
|
@ -71,7 +73,8 @@ extern "C" {
|
|||
#define _ARC_V2_STATUS32_Z (1 << 11)
|
||||
#define _ARC_V2_STATUS32_L (1 << 12)
|
||||
#define _ARC_V2_STATUS32_DZ (1 << 13)
|
||||
#define _ARC_V2_STATUS32_SC (1 << 14)
|
||||
#define _ARC_V2_STATUS32_SC_BIT 14
|
||||
#define _ARC_V2_STATUS32_SC (1 << _ARC_V2_STATUS32_SC_BIT)
|
||||
#define _ARC_V2_STATUS32_ES (1 << 15)
|
||||
#define _ARC_V2_STATUS32_RB(x) ((x) << 16)
|
||||
#define _ARC_V2_STATUS32_IE (1 << 31)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue