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
|
FIRQs and regular IRQs have different stacks so that a FIRQ can start
|
||||||
running without doing stack switching in software.
|
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
|
config FAULT_DUMP
|
||||||
int
|
int
|
||||||
prompt "Fault dump level"
|
prompt "Fault dump level"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
cflags-y += $(call cc-option,-ffunction-sections,) $(call cc-option,-fdata-sections,)
|
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,)
|
cflags-$(CONFIG_LTO) = $(call cc-option,-flto,)
|
||||||
|
|
||||||
include $(srctree)/arch/$(ARCH)/soc/$(SOC_NAME)/Makefile
|
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.
|
* LP_COUNT/LP_END registers, which are not banked.
|
||||||
*
|
*
|
||||||
* If all FIRQ ISRs are programmed such that there are no use of the LP
|
* 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
|
* registers (ie. no LPcc instruction), and CONFIG_ARC_STACK_CHECKING is
|
||||||
* remove the use of _firq_enter().
|
* 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
|
* When entering a FIRQ, interrupts might as well be locked: the processor is
|
||||||
* running at its highest priority, and cannot be preempted by anything.
|
* 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)
|
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
|
#ifndef CONFIG_FIRQ_NO_LPCC
|
||||||
/*
|
/*
|
||||||
* Unlike the rest of context switching code, r2 is loaded with something
|
* Unlike the rest of context switching code, r2 is loaded with something
|
||||||
|
@ -184,6 +191,13 @@ _firq_reschedule:
|
||||||
ld r3, [r2, __tTCS_link_OFFSET]
|
ld r3, [r2, __tTCS_link_OFFSET]
|
||||||
st r3, [r1, __tNANO_fiber_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 expects incoming thread in r2.
|
||||||
* _load_callee_saved_regs restores the stack pointer.
|
* _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, intlock_key);
|
||||||
GEN_OFFSET_SYM(tTCS, relinquish_cause);
|
GEN_OFFSET_SYM(tTCS, relinquish_cause);
|
||||||
GEN_OFFSET_SYM(tTCS, return_value);
|
GEN_OFFSET_SYM(tTCS, return_value);
|
||||||
|
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||||
|
GEN_OFFSET_SYM(tTCS, stack_top);
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_THREAD_CUSTOM_DATA
|
#ifdef CONFIG_THREAD_CUSTOM_DATA
|
||||||
GEN_OFFSET_SYM(tTCS, custom_data);
|
GEN_OFFSET_SYM(tTCS, custom_data);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -51,6 +51,12 @@ GTEXT(_rirq_exit)
|
||||||
SECTION_FUNC(TEXT, _rirq_enter)
|
SECTION_FUNC(TEXT, _rirq_enter)
|
||||||
|
|
||||||
mov r1, _nanokernel
|
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]
|
ld r2, [r1, __tNANO_current_OFFSET]
|
||||||
#if CONFIG_NUM_REGULAR_IRQ_PRIO_LEVELS == 1
|
#if CONFIG_NUM_REGULAR_IRQ_PRIO_LEVELS == 1
|
||||||
st sp, [r2, __tTCS_preempReg_OFFSET + __tPreempt_sp_OFFSET]
|
st sp, [r2, __tTCS_preempReg_OFFSET + __tPreempt_sp_OFFSET]
|
||||||
|
@ -126,6 +132,13 @@ _rirq_reschedule:
|
||||||
ld r3, [r2, __tTCS_link_OFFSET]
|
ld r3, [r2, __tTCS_link_OFFSET]
|
||||||
st r3, [r1, __tNANO_fiber_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 expects incoming thread in r2.
|
||||||
* _load_callee_saved_regs restores the stack pointer.
|
* _load_callee_saved_regs restores the stack pointer.
|
||||||
|
|
|
@ -86,6 +86,11 @@ SECTION_FUNC(TEXT, _Swap)
|
||||||
*/
|
*/
|
||||||
lr r3, [_ARC_V2_STATUS32]
|
lr r3, [_ARC_V2_STATUS32]
|
||||||
push_s r3
|
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
|
push_s blink
|
||||||
|
|
||||||
_save_callee_saved_regs
|
_save_callee_saved_regs
|
||||||
|
@ -118,7 +123,13 @@ _finish_swapping_to_thread:
|
||||||
ld r3, [r2, __tTCS_flags_OFFSET]
|
ld r3, [r2, __tTCS_flags_OFFSET]
|
||||||
st r3, [r1, __tNANO_flags_OFFSET]
|
st r3, [r1, __tNANO_flags_OFFSET]
|
||||||
#endif
|
#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 ? */
|
/* XXX - can be moved to delay slot of _CAUSE_RIRQ ? */
|
||||||
st r2, [r1, __tNANO_current_OFFSET]
|
st r2, [r1, __tNANO_current_OFFSET]
|
||||||
|
|
||||||
|
@ -168,11 +179,23 @@ _swap_return_from_firq:
|
||||||
bbit1 ilink, _ARC_V2_STATUS32_AE_BIT, _return_from_exc
|
bbit1 ilink, _ARC_V2_STATUS32_AE_BIT, _return_from_exc
|
||||||
|
|
||||||
ld ilink, [sp, -4] /* status32 into ilink */
|
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
|
and ilink, ilink, 0x7ffffffe // keep interrupts disabled until seti
|
||||||
|
#endif
|
||||||
kflag ilink
|
kflag ilink
|
||||||
|
|
||||||
ld ilink, [sp, -8] /* pc into 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]
|
j.d [ilink]
|
||||||
seti (_ARC_V2_DEF_IRQ_LEVEL | (1 << 4))
|
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
|
* enable the interrupts based on intlock_key
|
||||||
* value.
|
* 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);
|
pInitCtx->status32 = _ARC_V2_STATUS32_E(_ARC_V2_DEF_IRQ_LEVEL);
|
||||||
|
#endif
|
||||||
tcs->link = NULL;
|
tcs->link = NULL;
|
||||||
tcs->flags = priority == -1 ? TASK | PREEMPTIBLE : FIBER;
|
tcs->flags = priority == -1 ? TASK | PREEMPTIBLE : FIBER;
|
||||||
tcs->prio = priority;
|
tcs->prio = priority;
|
||||||
|
|
|
@ -194,6 +194,9 @@ struct tcs {
|
||||||
#ifdef CONFIG_ERRNO
|
#ifdef CONFIG_ERRNO
|
||||||
int errno_var;
|
int errno_var;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||||
|
uint32_t stack_top;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct s_NANO {
|
struct s_NANO {
|
||||||
|
|
|
@ -46,6 +46,8 @@ extern "C" {
|
||||||
#define _ARC_V2_IRQ_PRIO_PEND 0x200
|
#define _ARC_V2_IRQ_PRIO_PEND 0x200
|
||||||
#define _ARC_V2_AUX_IRQ_HINT 0x201
|
#define _ARC_V2_AUX_IRQ_HINT 0x201
|
||||||
#define _ARC_V2_IRQ_PRIORITY 0x206
|
#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_ERET 0x400
|
||||||
#define _ARC_V2_ERSTATUS 0x402
|
#define _ARC_V2_ERSTATUS 0x402
|
||||||
#define _ARC_V2_ECR 0x403
|
#define _ARC_V2_ECR 0x403
|
||||||
|
@ -71,7 +73,8 @@ extern "C" {
|
||||||
#define _ARC_V2_STATUS32_Z (1 << 11)
|
#define _ARC_V2_STATUS32_Z (1 << 11)
|
||||||
#define _ARC_V2_STATUS32_L (1 << 12)
|
#define _ARC_V2_STATUS32_L (1 << 12)
|
||||||
#define _ARC_V2_STATUS32_DZ (1 << 13)
|
#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_ES (1 << 15)
|
||||||
#define _ARC_V2_STATUS32_RB(x) ((x) << 16)
|
#define _ARC_V2_STATUS32_RB(x) ((x) << 16)
|
||||||
#define _ARC_V2_STATUS32_IE (1 << 31)
|
#define _ARC_V2_STATUS32_IE (1 << 31)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue